can1357/oh-my-pi · error · Error
Python execution is unavailable while session disposal is in
Error message
Python execution is unavailable while session disposal is in progress
What it means
EvalRunner.assertExecutionAllowed() guards against starting new Python/eval work once the session's disposal sequence has begun. Once #disposing is set, executePython() and execution() throw this synchronously instead of queueing work that could never complete or would race the teardown.
Source
Thrown at packages/coding-agent/src/session/eval-runner.ts:93
});
const result = await executePythonCommand(code, {
cwd,
sessionId: namespacePythonSessionId(sessionId),
kernelOwnerId: this.#kernelOwnerId,
kernelMode: this.#host.settings.get("python.kernelMode"),
interpreter: this.#host.settings.get("python.interpreter")?.trim() || undefined,
onChunk,
signal: abortController.signal,
});
this.recordPythonResult(code, result, options);
return result;
})();
return await this.trackExecution(execution, abortController);
}
/** Rejects new eval work once session disposal begins. */
assertExecutionAllowed(): void {
if (this.#disposing) throw new Error("Python execution is unavailable while session disposal is in progress");
}
/** Tracks externally started Python work so disposal can await and abort it. */
trackExecution<T>(execution: Promise<T>, abortController: AbortController): Promise<T> {
this.#abortControllers.add(abortController);
this.#activeExecutions.add(execution);
void execution.then(
() => {
this.#abortControllers.delete(abortController);
this.#activeExecutions.delete(execution);
},
() => {
this.#abortControllers.delete(abortController);
this.#activeExecutions.delete(execution);
},
);
return execution;
}View on GitHub (pinned to 9690622007)
Solutions
- Check a disposed flag / isDisposed before invoking executePython and skip the work
- Await dispose() completion before letting pending tasks run, or cancel pending tasks at shutdown start
- Wrap late calls in try-catch and treat this error as an expected shutdown signal, not a bug
- Reorder teardown so eval work is drained/aborted before disposal begins
Example fix
// before
await evalRunner.executePython(code); // throws during shutdown
// after
if (session.isDisposed()) return; // or AbortSignal check
try {
await evalRunner.executePython(code);
} catch (e) {
if (!(e instanceof Error && e.message.includes('disposal is in progress'))) throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// gate calls on session liveness: // if (session.isDisposed()) return; // skip eval work on a dying session
Try / catch
try {
const result = await evalRunner.executePython(code);
} catch (err) {
if (err instanceof Error && err.message.includes('disposal is in progress')) {
return null; // expected during shutdown — abort quietly
}
throw err;
} Prevention
- Pass an AbortSignal linked to session disposal into long-running agent loops
- Cancel or await in-flight eval work before calling dispose()
- Never schedule new tool/eval calls from timers that outlive the session
- In tests, await session teardown before ending the test to avoid stray callbacks
When it happens
Trigger: Calling evalRunner.executePython(...) or evalRunner.execution(...) after dispose() has started on the session — e.g. a background task, timer, or streaming response that fires code execution while the app is shutting the session down.
Common situations: App shutdown or session switch while an agent loop is still mid-turn; a queued follow-up tool call executing after the user aborted/disposed; tests tearing down a session while async callbacks still fire.
Related errors
- Recipient session is disposed.
- Cannot set cwd on a disposed JS runtime
- Command aborted
- Server "${name}" was disconnected during initial connection
- Server "${name}" was disconnected during reconnection
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/34e0c67f17afca79.
Report an issue: GitHub.