fix(server): stop reporting domain-reload cancellation as a request error - #49
Merged
Winlifes merged 1 commit intoAug 10, 2026
Conversation
A request in flight when Unity unloads the scripting domain logged "Error handling request: A task was canceled." and answered -32603 Internal error. Disposing the editor-thread pump (the DI container is disposed on beforeAssemblyReload, and MCPServerService disposes it on stop) cancels queued work, so the awaiting request observes a TaskCanceledException that the catch-all treated as a failure. Recognise cancellation as a stop/reload condition: log it through PluginDebugLogger and answer with the broker's backend-unavailable payload (-32001, retryable: true, reason: unity_backend_reloading) so clients see one shape for this condition. Nothing here is cancellable per request (HandleRequestAsync takes a default token and no tool raises OperationCanceledException), so no real failure is reclassified. Adds three EditMode tests, including one that ties a disposed pump's cancellation to the new classification.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Any MCP request that is still in flight when Unity unloads the scripting domain is reported as a server error:
This shows up during ordinary work — a script recompile,
request_recompile,execute_code's pre-refresh, a Play Mode transition — and reads like a plugin failure even though nothing failed.Root cause
The message wording pins the source:
A task was canceled.isTaskCanceledException's message (anOperationCanceledExceptionthrown by hand would read "The operation was canceled."), i.e.awaiton aTaskCompletionSourcethat was cancelled.EditorThreadHelperLifecycleTestsalready covers the cancellation source (ExecuteAsyncOnEditorThreadAsync_CancelsQueuedOuterTaskWhenDisposed,..._RejectsNewWorkAfterDispose); what was missing is the request handler recognising that cancellation for what it is.Two consequences: console noise (and an interrupted Error Pause / a false positive in CI log scans), plus the client receiving
-32603 Internal errorfor a transient, retryable condition — while the broker returns-32001 … retryable: truefor exactly the same situation.Change
HandleRequestReceivedgains a cancellation filter ahead of the catch-all: log throughPluginDebugLoggerinstead ofDebug.LogError, and answer with the broker's backend-unavailable payload (-32001,retryable: true,reason: unity_backend_reloading) so a client sees the same shape whether the broker or the in-process server answers.This cannot mask a genuine failure: nothing in this path is cancellable per request —
HandleRequestAsyncis called with adefaulttoken, and no tool underEditor/ToolsraisesOperationCanceledException/TaskCanceledException— so a cancellation here can only mean the editor-thread pump went away, i.e. stop or domain reload.The neighbouring "handler is null" path was intentionally left at
-32000 MCP server is stopping or not ready.to keep this change to one behaviour.Tests
Three new EditMode tests:
DisposedPumpRaisesTheCancellationTheServerTreatsAsShutdown— ties the two halves together: disposing a realEditorThreadHelperwith queued work makes the awaiting caller observeTaskCanceledException, andIsShutdownCancellationclassifies it.ShutdownCancellation_CoversTaskCancellationButNotRealFailures—TaskCanceledException/OperationCanceledExceptionclassify;InvalidOperationExceptionandnulldo not.BackendUnavailableResponse_MatchesBrokerRetryablePayload— code, message andretryable/reasondata match the broker'sBackendUnavailable*constants.Full
Funplay.Editor.TestsEditMode run is green on Unity 6000.3.13f1 apart from two failures that are pre-existing in this (very large) host project and unrelated to the change:CapabilityFunctionsTests.FindReferences_FindsPrefabAndHonorsScanLimit(the reverse-dependency scan budget of 5000 assets / 10 s is exhausted before it reaches the temp prefab) and a flakyHttpMCPTransportLifecycleTests.StartAsync_UnresponsivePortOwnerFailsWithoutReportingRunning(an unrelated Spine asset import error in the host project is caught as an unhandled log; passes on re-run).