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

  1. Read error.code for the category and error.cause (receipt) for spend details.
  2. Handle budget-exhaustion codes by raising maxCostUsd/budget or trimming the task.
  3. Retry transient provider/network codes with backoff.
  4. 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

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


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)