can1357/oh-my-pi · error · ToolError

${finalText} || Eval cell failed

Error message

${finalText} || Eval cell failed

What it means

When an eval cell runs as a managed auto-background job, the job wrapper inspects the final AgentToolResult. If result.isError === true (the cell failed, was cancelled, or timed out — a *completed* execution that errored), it re-throws a ToolError carrying the cell's final output text so the job manager records the job as failed and delivers the error text. This is how backend-level cell failures surface to the agent through the background-job path.

Source

Thrown at packages/coding-agent/src/tools/eval.ts:568

			label,
			async ({ jobId, signal: runSignal, reportProgress }) => {
				try {
					const result = await run(runSignal, (text, details) => {
						latestText = text;
						latestDetails = details;
						void reportProgress(text, { async: { state: "running", jobId, type: "eval" } });
						if (forwardUpdates) emitToolUpdate?.(text, details);
					});
					const finalText = result.content.find(block => block.type === "text")?.text ?? "";
					latestText = finalText;
					// Hand the full result (images included) to the foreground waiter
					// before deciding the job's terminal state.
					completion.resolve({ kind: "completed", result });
					if (result.isError === true) {
						// A failed, cancelled, or timed-out cell is a completed execution
						// that errored. Re-enter the failure path so the job manager
						// records it as failed and delivers the error text.
						throw new ToolError(finalText || "Eval cell failed");
					}
					await reportProgress(finalText, { async: { state: "completed", jobId, type: "eval" } });
					return finalText;
				} catch (error) {
					const message = error instanceof Error ? error.message : String(error);
					latestText = message;
					completion.resolve({ kind: "failed", error });
					await reportProgress(message, { async: { state: "failed", jobId, type: "eval" } });
					throw error;
				}
			},
			{ ownerId: session.getAgentId?.() ?? undefined },
		);

		if (startBackgrounded) {
			return this.#buildBackgroundStartResult(jobId, cells, languages, notice, latestText, latestDetails);
		}
		// Suppress the completion delivery up front so a job finishing while we

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the delivered error text: it is the cell's own output/exception; fix the user code that failed.
  2. Increase the cell timeout (params.timeout) if the failure was a timeout on long work.
  3. Disable auto-background (eval.autoBackground.enabled=false) if foreground execution with inline errors is preferred.

Example fix

// before: cell times out and is backgrounded
{ "language": "py", "code": "time.sleep(600)", "timeout": 10 }
// after: explicit longer timeout so it completes
{ "language": "py", "code": "time.sleep(600)", "timeout": 700 }
Defensive patterns

Strategy: try-catch

Type guard

function isEvalCellFailure(msg: string): boolean { return msg === "Eval cell failed" || msg.length > 0; } // the message is the cell's own output text

Try / catch

try {
  await evalTool.execute(id, params, signal);
} catch (e) {
  if (e instanceof ToolError) {
    const cellOutput = e.message; // final streamed cell text — inspect/repair the user code
    // retry with adjusted timeout or corrected code
  } else throw e;
}

Prevention

When it happens

Trigger: An auto-backgrounded eval cell completes with isError=true: the code itself threw, the cell timed out, or the cell was cancelled by the backend. The final text block content becomes the ToolError message.

Common situations: Long-running Python/JS cells that exceed timeout and get auto-backgrounded; user code with unhandled exceptions in backgrounded cells; backgrounded cells cancelled while waiting for the foreground result.

Related errors


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