can1357/oh-my-pi · error · Error
Python execution is unavailable while session disposal is…
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.
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.
- Browser runtime started without an active run
- Cannot set cwd on a disposed JS runtime
- Command aborted
- Failed to dispose one or more eval kernels
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/34e0c67f17afca79.
Report an issue: GitHub.
Appendix: 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)