I suppose that a hard limit on the number of carrier threads is a sensible choice then - deadlock is better than creating threads until the system grinds to a halt.
But then again, why couldn't scheduler detect a deadlock? Go has a system in place that, in case of total program deadlock, prints out an error message with all goroutines' stack traces, and stops the program. Perhaps Virtual Thread Scheduler could do the same thing?
But then again, Java also allows for native threads to run in parallel to Virtual Threads, which makes it impossible to detect whether there's a deadlock, and not just virtual threads waiting on a native thread.
I suppose this is a very good example why simple is better than complex.