can1357/oh-my-pi · warning · ToolError

${out}\n\n[${message}]

Error message

${out}\n\n[${message}]

What it means

When result.timedOut === true, BashTool throws a ToolError reporting the timeout. The message is 'Command timed out' or 'Command timed out after N seconds' (when the tool call specified a timeoutSec), and any captured output is prepended so the user sees what the command produced before it was killed.

Source

Thrown at packages/coding-agent/src/tools/bash.ts:664

	 */
	#throwIfUnfinished(
		result: BashResult | BashInteractiveResult,
		timeoutSec: number | undefined,
		outputText: string,
	): void {
		if (result.cancelled) {
			// Local executor output already carries a leading `[Command cancelled]`
			// notice from the sink; PTY/bridge output does not, so annotate only
			// the latter.
			const out = normalizeResultOutput(result);
			const annotated = out.startsWith("[Command cancelled]") ? out : out ? `${out}\n\n[Command aborted]` : out;
			throw new ToolError(annotated || "Command aborted");
		}
		if (result.timedOut === true) {
			const out = normalizeResultOutput(result);
			const message =
				timeoutSec === undefined ? "Command timed out" : `Command timed out after ${timeoutSec} seconds`;
			throw new ToolError(out ? `${out}\n\n[${message}]` : message);
		}
		if (result.exitCode === undefined) {
			throw new ToolError(`${outputText}\n\nCommand failed: missing exit status`);
		}
	}

	async #buildCompletedResult(
		result: BashResult | BashInteractiveResult,
		timeoutSec: number | undefined,
		options: {
			requestedTimeoutSec?: number;
			notices?: readonly string[];
			terminalId?: string;
			wallTimeMs?: number;
		} = {},
	): Promise<AgentToolResult<BashToolDetails>> {
		const exitCode = result.exitCode;
		const failedExit = exitCode !== undefined && exitCode !== 0;

View on GitHub (pinned to 9690622007)

Solutions

  1. Increase the timeoutSec parameter for legitimately long commands.
  2. Run long-lived processes in the background (nohup ... &, redirect logs) and poll them instead of blocking the tool call.
  3. Fix the command so it actually terminates — add its own timeouts, remove interactive prompts, pipe input.
  4. Disable pagers/interactive behavior with flags (e.g. --no-progress, CI=1, </dev/null) that commonly cause hangs.

Example fix

// before
await bash.run("npm install", {}); // hangs past default timeout
// after
await bash.run("npm install", { timeoutSec: 600 });
Defensive patterns

Strategy: try-catch

Try / catch

try { await bash.run(cmd, opts); } catch (e) { if (e instanceof ToolError && e.message.includes('Command timed out')) { /* raise timeoutSec, background the process, or fix the hang */ } else throw e; }

Prevention

When it happens

Trigger: The bash tool call exceeded its allowed runtime: a timeoutSec was supplied in the tool arguments and the command ran longer than it, or a default timeout fired (timeoutSec undefined).

Common situations: Long-running installs, builds, watches, servers, or interactive prompts (commands waiting on stdin) that never exit; network operations hanging without timeouts of their own.

Related errors


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