JuliusBrussee/caveman · error · CavemanRunError
<event.code>: <event.message>
Error message
<event.code>: <event.message>
What it means
runAgentWithOptions throws CavemanRunError built from the stream's run_error event, carrying the event's code and message plus the partial spend receipt as cause. This is the awaited-promise surface for run failures; the message shown is '<event.code>: <event.message>' with the actual event values substituted.
Solutions
- Read error.code for the category and error.cause (receipt) for spend details.
- Handle budget-exhaustion codes by raising maxCostUsd/budget or trimming the task.
- Retry transient provider/network codes with backoff.
- Log event.code + event.message to identify the underlying failing component.
Example fix
// before
const result = await run(agent, input); // unhandled CavemanRunError
// after
try {
const result = await run(agent, input);
} catch (e) {
if (e instanceof CavemanRunError) console.error(e.code, e.cause?.receipt);
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check budget before run
if (budget?.maxUsd !== undefined && estimatedCost > budget.maxUsd) {
throw new Error("estimated cost exceeds budget");
} Type guard
const isCavemanRunError = (e: unknown): e is CavemanRunError => e instanceof CavemanRunError;
Try / catch
try {
const result = await runAgent(definition, input);
} catch (e) {
if (isCavemanRunError(e)) {
console.error(`run failed [${e.code}]: ${e.message}`, e.cause?.receipt);
} else throw e;
} Prevention
- Set realistic budgets/maxCostUsd to avoid mid-run exhaustion.
- Inspect e.code/e.cause receipt to classify failures before retrying.
- Apply backoff retries only for transient provider/network codes.
- Monitor breaker state to anticipate run_error from open breakers.
When it happens
Trigger: The run stream emits a run_error event for any internal failure (budget exhaustion, breaker trip, provider error, tool failure) while consuming the stream in runAgentWithOptions.
Common situations: Max cost/token budget exhausted mid-run; circuit breaker opened; provider API failure; sandboxed tool crash. The receipt on cause lets you see spend up to the failure.
Related errors
- budget is below CCR storage minimum
- cave_breaker_retry_requires_budget
- cave_budget_cap_breached
- cave_budget_conflicting_cap
- cave_budget_controller_in_use
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/676977a844d0fad0.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/runtime.ts:998
async function runAgentWithOptions(
definition: AgentDefinition,
input: string,
options: InternalRunOptions,
executionContext: InternalExecutionContext,
): Promise<RunResult> {
let final: RunResult | undefined;
for await (const event of streamAgentWithOptions(
definition,
input,
options,
executionContext,
)) {
if (event.type === "run_end") final = event.result;
if (event.type === "run_error") {
// The ledger is not lost on the throwing path either: the partial receipt
// rides on a typed `cause` so a caller that only awaits the promise can
// still read what was spent before the failure.
throw new CavemanRunError(event.code, event.message, event.receipt);
}
}
if (!final) throw new Error("caveman agent: run ended without terminal evidence");
return final;
}
export function streamAgent(
definition: AgentDefinition,
input: string,
options: RunOptions = {},
): AsyncGenerator<CavemanRunEvent> {
rejectInternalRunOptions(options);
return streamAgentWithOptions(
definition,
input,
options,
rootExecutionContext(definition, options.maxCostUsd, options),
);View on GitHub (pinned to 3ee70a1026)