JuliusBrussee/caveman · error

cave_${slot}_budget_exceeded

cave_${slot}_budget_exceeded

Error message

cave_${slot}_budget_exceeded

What it means

Thrown by the budget-validation step of the Caveman agent runtime when a token bill for one prompt slot exceeds the allocation in the lowered plan (plan.budgets). The runtime splits the prompt into slots — memory, history, results_artifacts (artifact+skill+tool_result), and output — and enforces hard per-slot caps before assembling the request. It throws early with the slot name in the message so the caller knows which budget was blown.

Solutions

  1. Identify the slot named in the message (e.g. cave_history_budget_exceeded means history) and trim or compact that segment's content.
  2. Raise the corresponding budgets[slot] value in the plan/agent definition to a realistic ceiling.
  3. Enable or widen compaction/transform routes for the offending slot so content is reduced before budget validation.
  4. Check for runaway growth (unbounded tool_result accumulation) and cap tool output or drop old results.

Example fix

// before
plan.budgets = { memory: 1000, history: 2000, results_artifacts: 2000, output: 1000 };
// with a 3500-token history
// after
plan.budgets = { memory: 1000, history: 4000, results_artifacts: 2000, output: 1000 };
// or compact history before the run
Defensive patterns

Strategy: validation

Validate before calling

const slots = { memory: bill.memory ?? 0, history: bill.history ?? 0, results_artifacts: (bill.artifact ?? 0) + (bill.skill ?? 0) + (bill.tool_result ?? 0), output: outputMaxTokens };
for (const [slot, used] of Object.entries(slots)) {
  if (used > plan.budgets[slot]) console.warn(`slot ${slot} over budget: ${used} > ${plan.budgets[slot]}`);
}

Type guard

function withinBudget(used: number, budget: number | undefined): boolean { return typeof budget === "number" && used <= budget; }

Try / catch

try {
  await agent.run(input);
} catch (err) {
  if (err instanceof Error && /^cave_[a-z_]+_budget_exceeded$/.test(err.message)) {
    const slot = err.message.match(/^cave_([a-z_]+)_budget_exceeded$/)?.[1];
    // compact that slot or raise plan.budgets[slot], then retry
  } else throw err;
}

Prevention

When it happens

Trigger: Calling the agent run path with a bill whose value for a slot (memory, history, artifact/skill/tool_result totals) exceeds plan.budgets[slot], or whose planned outputMaxTokens exceeds the output budget. Any single slot over its cap trips the check in the slot loop.

Common situations: Injecting an oversized memory blob or accumulated history without compaction; many tool results/artifacts accumulating in one turn; a plan configured with tight budgets while the context naturally grew; upgrading agents without revisiting budget allocations.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/de9882d06f54b2ef. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/runtime.ts:2572

  }
  return ordered;
}

export function enforceSemanticBudgets(
  bill: Readonly<Record<string, number>>,
  outputMaxTokens: number,
  plan: CavePlan,
): void {
  const slots: Array<[keyof CavePlan["budgets"], number]> = [
    ["instructions", bill.instruction ?? 0],
    ["tools", bill.tool_schema ?? 0],
    ["memory", bill.memory ?? 0],
    ["history", bill.history ?? 0],
    ["results_artifacts", (bill.artifact ?? 0) + (bill.skill ?? 0) + (bill.tool_result ?? 0)],
    ["output", outputMaxTokens],
  ];
  for (const [slot, used] of slots) {
    if (used > plan.budgets[slot]) throw new Error(`cave_${slot}_budget_exceeded`);
  }
}

export function assembleSystemPrompt(
  definition: AgentDefinition,
  lowered: LoweredContext,
  bodies: ReadonlyMap<string, Uint8Array> = lowered.bodies,
): string {
  const decoder = new TextDecoder();
  const required = ["agent.instructions", ...definition.contexts.map((item) => item.id)];
  const parts: string[] = [];
  for (const id of required) {
    const segment = lowered.ir.segments.find((item) => item.id === id);
    if (!segment) throw new Error(`cave_context_segment_missing:${id}`);
    const body = bodies.get(segment.bodyHandle);
    if (!body) throw new Error(`cave_context_body_missing:${id}`);
    const text = decoder.decode(body);
    parts.push(id === "agent.instructions" ? text : `<cave-context id=${JSON.stringify(id)}>\n${text}\n</cave-context>`);

View on GitHub (pinned to 3ee70a1026)