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 TestJobManager.StartJob under a lock when _currentJobId is already set. The job manager enforces a single concurrent test run (single-slot) with a check-and-set inside one lock scope to avoid a TOCTOU race. This is the outer guard; TestRunnerService has its own inner guard (error 58).
Source
Thrown at MCPForUnity/Editor/Services/TestJobManager.cs:337
LastUpdateUnixMs = started,
TotalTests = null,
CompletedTests = 0,
CurrentTestFullName = null,
CurrentTestStartedUnixMs = null,
LastFinishedTestFullName = null,
LastFinishedUnixMs = null,
FailuresSoFar = new List<TestJobFailure>(),
Error = null,
Result = null,
InitTimeoutMs = initTimeoutMs
};
// Single lock scope for check-and-set to avoid TOCTOU race
lock (LockObj)
{
if (!string.IsNullOrEmpty(_currentJobId))
{
throw new InvalidOperationException("A Unity test run is already in progress.");
}
Jobs[jobId] = job;
_currentJobId = jobId;
}
PersistToSessionState(force: true);
// Kick the run (must be called on main thread; our command handlers already run there).
Task<TestRunResult> task = MCPServiceLocator.Tests.RunTestsAsync(mode, filterOptions);
void FinalizeJob(Action finalize)
{
// Ensure state mutation happens on main thread to avoid Unity API surprises.
EditorApplication.delayCall += () =>
{
try { finalize(); }
catch (Exception ex) { McpLog.Error($"[TestJobManager] Finalize failed: {ex.Message}\n{ex.StackTrace}"); }
};
}View on GitHub (pinned to c21bf496bc)
Solutions
- Poll the existing job with get_test_status until it finishes before starting another run.
- If the job is a zombie (status stuck, no real run), the finalization safety net should clear it; if not, restart the Unity Editor to reset session state.
- Serialize run_tests calls from multiple agents with a queue/lock on the caller side.
Defensive patterns
Strategy: validation
Validate before calling
// Check for an active job before starting a new one.
if (!string.IsNullOrEmpty(TestJobManager.CurrentJobId)) // or expose an IsBusy flag
return ErrorResponse("A test run is in progress; poll get_test_status before starting another."); Try / catch
try { return TestJobManager.StartJob(mode, opts); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already in progress"))
{ /* poll existing job; queue or reject the new request */ } Prevention
- Poll get_test_status until the current job finishes before issuing run_tests again.
- Serialize run_tests across multiple agents with a caller-side queue.
- If a job is stuck (zombie), restart the Editor to reset session state.
When it happens
Trigger: Two run_tests invocations issued before the first finalized (multi-agent concurrency); a previous run whose FinalizeCurrentJobFromRunFinished/continuation never cleared _currentJobId; a PlayMode run still in progress.
Common situations: Two AI agents calling run_tests near-simultaneously; a previous job left as a zombie after a crash; a long PlayMode run still active when a second request arrives.
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/2a816c83c6e5ae57.
Report an issue: GitHub.