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

  1. Increase the command deadline/timeout for workloads that legitimately restart kernels
  2. Reduce shutdown hang time (the code already bounds it with `getRemainingTimeoutMs`) — investigate why the old kernel shutdown stalls
  3. 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

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

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/d4d282a5d9dcbe1c. Report an issue: GitHub.