can1357/oh-my-pi · error · ToolError
agent() blocked: turn token budget exhausted (${turnBudget.s
Error message
agent() blocked: turn token budget exhausted (${turnBudget.spent}/${turnBudget.total} output tokens). Raise or drop the +Nk! ceiling to continue. What it means
The eval session can impose a hard per-turn output-token ceiling (+Nk!). Before spawning a subagent, the bridge checks the turn budget and refuses agent() calls once spent tokens reach the total, so a runaway eval cannot exceed the cap. The message tells you to raise or remove the hard ceiling.
Source
Thrown at packages/coding-agent/src/eval/agent-bridge.ts:128
function buildSubagentFailureMessage(agentName: string, result: SingleResult): string {
const abortReason = trimToUndefined(result.abortReason);
if (result.aborted && abortReason) return abortReason;
return (
trimToUndefined(result.error) ??
trimToUndefined(result.stderr) ??
abortReason ??
`agent() subagent '${agentName}' failed.`
);
}
/**
* Run a single subagent on behalf of an eval cell's `agent()` call.
*/
export async function runEvalAgent(args: unknown, options: EvalAgentBridgeOptions): Promise<EvalAgentResult> {
const parsed = parseAgentArgs(args);
const turnBudget = options.session.getTurnBudget?.();
if (turnBudget?.hard && turnBudget.total !== null && turnBudget.spent >= turnBudget.total) {
throw new ToolError(
`agent() blocked: turn token budget exhausted (${turnBudget.spent}/${turnBudget.total} output tokens). Raise or drop the +Nk! ceiling to continue.`,
);
}
const isolation =
Object.hasOwn(parsed, "isolated") || Object.hasOwn(parsed, "apply") || Object.hasOwn(parsed, "merge")
? {
...(parsed.isolated !== undefined ? { requested: parsed.isolated } : {}),
...(parsed.merge === false ? { merge: "patch" as const } : {}),
...(parsed.apply !== undefined ? { apply: parsed.apply } : {}),
}
: undefined;
try {
const execution = await withBridgeTimeoutPause(
options.emitStatus,
() =>
runStructuredSubagent({
session: options.session,View on GitHub (pinned to 9690622007)
Solutions
- Raise the hard ceiling, e.g. +50k! instead of +10k!
- Drop the ! to make the budget soft (advisory) if a hard cap isn't needed
- Restructure the eval to use fewer/smaller agent() calls
- Split the work across turns so each turn gets a fresh budget
Example fix
// before (tight hard ceiling drains before agent())
// eval header: budget +10k!
agent({ prompt: 'refactor module' })
// after: raise or soften
// eval header: budget +100k! (or +100k for soft)
agent({ prompt: 'refactor module' }) Defensive patterns
Strategy: validation
Validate before calling
const tb = session.getTurnBudget?.();
if (tb?.hard && tb.total !== null && tb.spent >= tb.total) console.warn('budget exhausted; raise +Nk! before agent()'); Type guard
null
Try / catch
try { await agent(args) } catch (e) { if (/turn token budget exhausted/.test(e.message)) { raiseBudgetAndRetry(); } else throw e } Prevention
- Size the +Nk! ceiling above expected subagent usage
- Reserve budget: call agent() early in the turn
- Avoid agent() inside unbounded loops
- Use a soft budget (no !) when a hard cap is not required
When it happens
Trigger: Calling agent() in an eval when the session's hard turn budget is fully spent (spent >= total, total !== null) — e.g. after many prior tool calls or large outputs consumed the +Nk! allocation.
Common situations: Eval configured with a tight +10k! hard budget but the workflow needs subagents late in the turn; loops calling agent() repeatedly until the budget is drained; forgot the ! makes the cap hard.
Related errors
- ${failureMessage}${recoveryHint} (subagent failure: ${policy
- agent() isolated apply failed for ${result.id}${summary ? `:
- agent() isolated nested patch apply failed for ${result.id}:
- ${error.message} (rethrown as ToolError from StructuredSubag
- Too many pending authorization requests. Please try again la
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a01c3b88b6002d10.
Report an issue: GitHub.