You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commands sent while the Editor main thread is blocked wait silently instead of failing fast, although status already reports MainThreadBlocked #3411
When the Editor main thread is blocked, for example by a modal dialog, uloop status correctly reports MainThreadBlocked. But a command sent at that time takes the slot and waits without any message until the main thread resumes. If the block is a dialog nobody answers, the caller waits until the command's own timeout.
Reproduction
Schedule a 60 s main-thread block 5 s from now:
uloop execute-dynamic-code --code 'var at = UnityEditor.EditorApplication.timeSinceStartup + 5; UnityEditor.EditorApplication.CallbackFunction f = null; f = () => { if (UnityEditor.EditorApplication.timeSinceStartup < at) return; UnityEditor.EditorApplication.update -= f; System.Threading.Thread.Sleep(60000); }; UnityEditor.EditorApplication.update += f; return "scheduled";'
After about 9 s, uloop status returns "State": "MainThreadBlocked" with SecondsSinceLastMainThreadTick around 8.
Run uloop get-hierarchy --max-depth 1. It returns Success: true after 52 s, only once the block ends. Nothing is reported while it waits.
By contrast, a command sent while another command holds the slot during a block fails fast, in about 11 s, with a clear UNITY_SERVER_BUSY message ("waiting for the Editor main thread, which has not responded for 45s ..."). So the blocked state is already detected. It is just not used for the command that holds the slot.
Impact
Agents driving uloop see a command that hangs with no output and can't tell whether to wait, cancel or check the screen. In my project, I work around this with a wrapper that polls uloop status alongside each command. If RunningToolPhase stays WaitingForMainThread, or the main thread stays silent, for about 30 s, the wrapper kills the CLI and tells the agent to look for a dialog.
Expected
If the main thread stays blocked past a threshold while a command waits for it, return an error such as MAIN_THREAD_BLOCKED with the blocked duration and the same guidance status and UNITY_SERVER_BUSY already give (check for a modal dialog, restart only if it persists), instead of waiting until the timeout.
Related
Issue 2320 and the compile stall warning added by its follow-up PRs. That warning covers compile. This issue is about commands in general, which still give no signal while blocked.
changed the title [-]Commands sent while the Editor main thread is blocked wait silently instead of failing fast, although status already reports MainThreadBlocked[/-][+]Commands sent while the Editor main thread is blocked wait silently instead of failing fast, although `status` already reports `MainThreadBlocked`[/+]on Oct 28, 2026
Thank you for the report, and especially for the reproduction snippet and the observation that UNITY_SERVER_BUSY already carried the stall; both went straight into the fix.
Released today in two parts:
Unity package 3.21.2 (fix: Commands sent while a dialog blocks the Unity Editor now fail fast with MAIN_THREAD_BLOCKED instead of waiting silently #3417): a command that is holding the slot but has not entered its tool code yet is failed by the Editor once the main thread has stalled for 30 seconds. The stall is measured from the last main-thread tick, not from the moment the command was sent, so a dialog that has been up for a while fails the command within a second or two. The slot is released, the response says '<tool>' was not run: the Unity Editor main thread has not run for 30s, so uloop stopped waiting and released the command slot., and the error details carry type: main_thread_blocked, stallSeconds, and runningToolName. With your 60-second block, uloop get-hierarchy sent at stall 7s now exits 1 after about 23 seconds instead of succeeding after 52. A command whose own code blocks the main thread is not stopped, and uloop status keeps answering throughout.
Updating the package to 3.21.3 is enough; the CLI picks up the matching runner on the next command.
The 30-second threshold matches the CLI's existing stall notice and compile's silent-wait warning; the reasoning and the conditions for changing it are in docs/adr/0020-blocked-main-thread-fails-the-waiting-command.md. If it turns out to be too long or too short in your project, please say so here.
Activity
[-]Commands sent while the Editor main thread is blocked wait silently instead of failing fast, although status already reports MainThreadBlocked[/-][+]Commands sent while the Editor main thread is blocked wait silently instead of failing fast, although `status` already reports `MainThreadBlocked`[/+]hatayama commentedon Oct 29, 2026
Thank you for the report, and especially for the reproduction snippet and the observation that
UNITY_SERVER_BUSYalready carried the stall; both went straight into the fix.Released today in two parts:
'<tool>' was not run: the Unity Editor main thread has not run for 30s, so uloop stopped waiting and released the command slot., and the error details carrytype: main_thread_blocked,stallSeconds, andrunningToolName. With your 60-second block,uloop get-hierarchysent at stall 7s now exits 1 after about 23 seconds instead of succeeding after 52. A command whose own code blocks the main thread is not stopped, anduloop statuskeeps answering throughout.MAIN_THREAD_BLOCKEDwithSafeToRetry: trueand the same guidancestatusgives (look for a modal dialog,uloop focus-window,uloop statusand then send the command once more,uloop launch -ronly if it persists). The existing 30-second "Unity main thread stuck" notice is also written to stderr as a plain line now, even when stderr is not a terminal, so an agent reading through a pipe sees why a command is waiting.Updating the package to 3.21.3 is enough; the CLI picks up the matching runner on the next command.
The 30-second threshold matches the CLI's existing stall notice and compile's silent-wait warning; the reasoning and the conditions for changing it are in
docs/adr/0020-blocked-main-thread-fails-the-waiting-command.md. If it turns out to be too long or too short in your project, please say so here.