can1357/oh-my-pi · warning · PythonExecutionCancelledError
Command timed out
Error message
Command timed out
What it means
After shutting down the old kernel, `replaceSessionKernel` checks the deadline: if `replacement.deadlineMs` is set and already passed (`deadlineMs <= Date.now()`), it throws `PythonExecutionCancelledError(true)` with message "Command timed out". This prevents starting a brand-new kernel on behalf of a command whose time budget has already expired.
Source
Thrown at packages/coding-agent/src/eval/py/executor.ts:254
) {
throw new PythonExecutionCancelledError(false);
}
const deferred = Promise.withResolvers<PythonKernel>();
const replacement: SessionKernelReplacement = {
generation,
deadlineMs: options.deadlineMs,
promise: deferred.promise,
};
session.replacement = replacement;
void (async () => {
try {
const remaining = getRemainingTimeoutMs(options.deadlineMs);
await kernel
.shutdown(remaining !== undefined ? { timeoutMs: Math.max(0, remaining) } : undefined)
.catch(() => undefined);
if (replacement.deadlineMs !== undefined && replacement.deadlineMs <= Date.now()) {
throw new PythonExecutionCancelledError(true);
}
if (
context.sessions.get(session.sessionKey) !== session ||
session.generation !== generation ||
session.kernel !== kernel
) {
throw new PythonExecutionCancelledError(false);
}
const next = await startKernel(cwd, {
...options,
signal: undefined,
deadlineMs: undefined,
});
if (
context.sessions.get(session.sessionKey) !== session ||
session.generation !== generation ||
session.kernel !== kernel
) {View on GitHub (pinned to 9690622007)
Solutions
- Increase the command deadline/timeout for workloads that legitimately restart kernels
- Reduce shutdown hang time (the code already bounds it with `getRemainingTimeoutMs`) — investigate why the old kernel shutdown stalls
- Handle PythonExecutionCancelledError with timedOut=true distinctly: report timeout to the user instead of retrying
Example fix
// before
callPython(code, { deadlineMs: Date.now() + 1000 }); // too tight for restart
// after
callPython(code, { deadlineMs: Date.now() + 30000 }); // budget covers kernel restart Defensive patterns
Strategy: validation
Validate before calling
const deadlineMs = Date.now() + budgetMs;
if (budgetMs < MIN_RESTART_BUDGET_MS) {
throw new Error(`deadline ${budgetMs}ms too small for possible kernel restart`);
} Try / catch
try {
return await runPython(code, { deadlineMs });
} catch (err) {
if (err instanceof PythonExecutionCancelledError && err.timedOut) {
// report timeout to user; optionally retry with a larger budget
throw new TimeoutError(`exceeded ${deadlineMs - (deadlineMs - budgetMs)}ms budget`);
}
throw err;
} Prevention
- Give deadlines enough headroom to include a full kernel shutdown + restart
- Avoid launching work whose remaining budget is nearly spent
- Investigate kernel shutdown hangs that consume the budget
When it happens
Trigger: Kernel replacement taking longer than the caller's deadline (old kernel shutdown hung and consumed `remaining` time), so by the time a new kernel would start, the budget is exhausted.
Common situations: Shutdown of a wedged kernel process blocking until the deadline passes; very tight timeouts combined with slow process teardown; slow machine/filesystem making restart exceed the budget.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Command aborted
- Python kernel unavailable
- Failed to dispose one or more eval kernels
- Overall trial deadline exceeded (${Math.round(deadlineMs / 1
- timed out: {command}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d4d282a5d9dcbe1c.
Report an issue: GitHub.