JuliusBrussee/caveman · warning
cave_run_stopped
cave_run_stopped
Error message
cave_run_stopped
What it means
Thrown by streamFn when modelCalls reaches maxModelCalls (the caller override or the derived default). This is a stop condition, not a failure: stopReason is set to "call_budget_exhausted" and refusalPending records the refusal, so the run ends through the graceful path with partial work and the receipt intact. Exactly maxModelCalls calls are allowed — the check runs before the increment.
Source
Thrown at packages/agent/src/runtime.ts:1600
if (usageFailure) throw usageFailure;
if (nestedUsage.incomplete) throw new Error("cave_nested_usage_incomplete");
if (efficiencyPlan && reasoningUsageUnavailable) {
throw new Error("cave_reasoning_usage_unavailable");
}
if (efficiencyPlan) {
enforceSemanticBudgets(contextBill(lowered.ir), outputTokens, efficiencyPlan);
if (reasoningTokens > efficiencyPlan.budgets.reasoning) {
throw new Error("cave_reasoning_budget_exceeded");
}
}
// The hard model-call ceiling is a stop condition, not a failure: ending
// the run through the same graceful path as every other stop keeps the
// partial work and the receipt intact. Checked before the
// increment so exactly `maxModelCalls` calls are allowed.
if (modelCalls >= maxModelCalls) {
stopReason = "call_budget_exhausted";
refusalPending = true;
throw new Error("cave_run_stopped");
}
modelCalls++;
// Between-calls stop point. Nothing is in flight here: the previous turn
// and its tools have finished and settled, and this call has not started.
const plan = () => decideNextCall({
meter: budgetMeter,
breakers,
deadlineAt,
selected,
context,
requestedOutputTokens: streamOptions?.maxTokens,
outputMaxTokens: definition.output?.maxTokens,
planOutputTokens: efficiencyPlan?.budgets.output,
restorableBytes: restorableRequestBytes(
conversationOriginals,
instructions,
originalInstructions,
),View on GitHub (pinned to 27d5a3981a)
Solutions
- Raise the ceiling: run(input, { maxModelCalls: N }) with an integer >= 1
- Inspect RunResult.stopReason === "call_budget_exhausted" and the receipt to see which tool loop consumed the calls, then fix the agent's instructions/tool design so it converges
- Enable breakers (RunOptions.breakers) to catch repeated-tool-call loops before they eat the call ceiling
Example fix
// before
await agent.run(input, { maxModelCalls: 4 }); // throws cave_run_stopped mid-task
// after
const result = await agent.run(input, { maxModelCalls: 16 });
if (result.stopReason === "call_budget_exhausted") {
// handle partial work using result and result.receipt
} Defensive patterns
Strategy: fallback
Validate before calling
// Size the ceiling before the run from expected turn count.
const expectedTurns = estimateTurns(task); // your own heuristic
const opts = { maxModelCalls: Math.max(8, expectedTurns * 2) }; Try / catch
let result;
try {
result = await agent.run(input, opts);
} catch (e) {
if (e instanceof Error && e.message === "cave_run_stopped") {
// graceful stop: the framework records stopReason; if you caught it here,
// read the result/stopReason path your wrapper exposes and treat partial
// output as usable, optionally retrying with a raised ceiling
} else throw e;
} Prevention
- Always read RunResult.stopReason instead of only catching throws
- Set maxModelCalls with headroom over expected turns
- Enable breakers to surface tool loops that waste call budget
When it happens
Trigger: A tool-looping conversation hitting the default ceiling of 64 model calls (no plan), or the plan-derived ceiling; or hitting a caller-set maxModelCalls: N.
Common situations: Agents that loop on tools without converging; ceilings set too low for the task's natural turn count; plans whose retry_cascade_reserve implies a small call ceiling.
Related errors
- option not found
- cave_harness_adapter_version_invalid
- cave_harness_upstream_version_invalid
- cave_harness_artifact_digest_invalid
- cave_harness_request_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/47b8075cc2946cd8.
Report an issue: GitHub.