CoplayDev/unity-mcp · error · InvalidOperationException
A Unity test run is already in progress.
Error message
A Unity test run is already in progress.
What it means
Thrown by TestRunnerService.RunTestsAsync (inside the held _operationLock) when _runCompletionSource is non-null and not yet completed. This is the runner-level single-flight guard; it complements the job-manager guard (error 57). An orphaned completion source after a crashed run can also trip it.
Source
Thrown at MCPForUnity/Editor/Services/TestRunnerService.cs:199
}
finally
{
_operationLock.Release();
}
}
public async Task<TestRunResult> RunTestsAsync(TestMode mode, TestFilterOptions filterOptions = null)
{
await _operationLock.WaitAsync().ConfigureAwait(true);
Task<TestRunResult> runTask;
bool adjustedPlayModeOptions = false;
bool originalEnterPlayModeOptionsEnabled = false;
EnterPlayModeOptions originalEnterPlayModeOptions = EnterPlayModeOptions.None;
try
{
if (_runCompletionSource != null && !_runCompletionSource.Task.IsCompleted)
{
throw new InvalidOperationException("A Unity test run is already in progress.");
}
if (EditorApplication.isPlaying || EditorApplication.isPlayingOrWillChangePlaymode)
{
throw new InvalidOperationException("Cannot start a test run while the Editor is in or entering Play Mode. Stop Play Mode and try again.");
}
if (mode == TestMode.PlayMode)
{
// PlayMode runs transition the editor into play across multiple update ticks. Unity's
// built-in pipeline schedules SaveModifiedSceneTask early, but that task uses
// EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo which throws once play mode is
// active. To minimize that window we pre-save dirty scenes and disable domain reload (so the
// MCP bridge stays alive). We do NOT force runSynchronously here because that can freeze the
// editor in some projects. If the TestRunner still hits the save task after entering play, the
// run can fail; in that case, rerun from a clean Edit Mode state.
adjustedPlayModeOptions = EnsurePlayModeRunsWithoutDomainReload(
out originalEnterPlayModeOptionsEnabled,View on GitHub (pinned to c21bf496bc)
Solutions
- Wait for the existing run to finish before issuing another (poll via the job manager).
- If the TCS is orphaned (no real run active but the guard still throws), restart the Unity Editor to reset the service.
- Ensure any PlayMode run reaches RunFinished; if it deadlocks, stop Play Mode and let finalization clear state.
Defensive patterns
Strategy: validation
Validate before calling
// Gate on the runner's busy state before calling RunTestsAsync.
if (EditorApplication.isPlaying || EditorApplication.isPlayingOrWillChangePlaymode)
return ErrorResponse("Editor is in Play Mode; stop it before running tests."); Try / catch
try { return await tests.RunTestsAsync(mode, opts); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already in progress"))
{ /* wait for the existing run / restart editor if orphaned */ } Prevention
- Ensure each PlayMode run reaches RunFinished so the TCS completes; stop Play Mode if it deadlocks.
- Don't issue concurrent run_tests calls; the service is single-flight by design.
- Restart the Editor if the guard throws with no real run active (orphaned TCS).
When it happens
Trigger: A second RunTestsAsync while a previous run's TCS is incomplete; a previous run that crashed without completing/ disposing its TaskCompletionSource; the PlayMode path failing mid-run and leaving the TCS open.
Common situations: Concurrent run_tests calls; a PlayMode run that errored before RunFinished; editor crash mid-run leaving stale state.
Related errors
- A Unity test run is already in progress.
- Cannot start a test run while the Editor is in or entering P
- Port {port} is already in use.
- Preview generation was aborted due to a change of the scene
AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13).
Data as JSON: /api/errors/e0fdeda1e59c5bab.
Report an issue: GitHub.