{"record":{"id":"e210dad86df35eb9","repo":"JuliusBrussee/caveman","slug":"cave-subagent-context-budget","errorCode":"cave_subagent_context_budget","errorMessage":"cave_subagent_context_budget","messagePattern":"cave_subagent_context_budget","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":3952,"sourceCode":"    toolDefinition,\n    runtime,\n    task,\n    signal,\n    parentOptions,\n    usage,\n    executionContext,\n    depth,\n  } = input;\n  if (signal?.aborted) throw signal.reason;\n  const childDefinition = runtime.definition as AgentDefinition;\n  const childContext = await lowerAgentContext(childDefinition, {\n    ...(parentOptions.rootDir === undefined ? {} : { rootDir: parentOptions.rootDir }),\n    input: task,\n  });\n  const childContextTokens = childContext.ir.segments\n    .reduce((total, segment) => total + segment.tokenCount, 0);\n  if (childContextTokens > runtime.maxContextTokens) {\n    throw new Error(\"cave_subagent_context_budget\");\n  }\n  const childUsesAuto = childDefinition.model !== null &&\n    typeof childDefinition.model === \"object\" &&\n    \"kind\" in childDefinition.model &&\n    childDefinition.model.kind === \"auto\";\n  const childModel = childUsesAuto && parentOptions.model !== undefined\n    ? parentOptions.model\n    : resolveModel(\n      childDefinition,\n      parentOptions.models ?? builtinModels(),\n      parentOptions.rootDir ?? process.cwd(),\n    );\n  // A carved wallet is already the child's hard economic boundary in the\n  // parent's denomination. Stacking the legacy USD-only ledger on a token\n  // wallet would require catalog pricing and reject otherwise valid raw-token\n  // runs (including subscription/unpriced transports). Keep that ledger only\n  // for standalone legacy subagents that have no carved BudgetMeter.\n  let spendLedger: SpendLedger | undefined;","sourceCodeStart":3934,"sourceCodeEnd":3970,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/runtime.ts#L3934-L3970","documentation":"After building the child agent's context from its input, the runtime sums the token counts of the child context segments and enforces runtime.maxContextTokens. If the assembled child context exceeds that ceiling, cave_subagent_context_budget is thrown before any model call, keeping a subagent from starting with a context already over its budget.","triggerScenarios":"Dispatching a subagent whose task input causes childContext.ir.segments' total tokenCount to exceed runtime.maxContextTokens — typically a very large task string plus baseline context.","commonSituations":"Task text embedding large file contents; maxContextTokens configured below the runtime's own baseline context size; child inheriting a heavy system/context build from rootDir contents; cost-focused configs with tiny context budgets.","solutions":["Reduce the task input size (reference files instead of inlining them)","Raise runtime.maxContextTokens for the subagent runtime","Trim what the child context builder includes (narrow rootDir, fewer context segments)","Split the work across multiple smaller subagent calls"],"exampleFix":"// before\nruntime: { kind: \"subagent\", maxContextTokens: 8000 }\ndispatchSubagent({ task: entireLogFile });\n// after\nruntime: { kind: \"subagent\", maxContextTokens: 100000 }\ndispatchSubagent({ task: \"Analyze errors in \" + logPath });","handlingStrategy":"validation","validationCode":"const estTokens = Math.ceil(task.length / 4);\nif (estTokens > subagentRuntime.maxContextTokens) {\n  task = truncateToTokenBudget(task, subagentRuntime.maxContextTokens - baselineOverhead);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await dispatchSubagent({ task });\n} catch (e) {\n  if (e.message === \"cave_subagent_context_budget\") {\n    await dispatchSubagent({ task: condense(task) });\n  } else throw e;\n}","preventionTips":["Keep task inputs well below maxContextTokens (reserve room for system/context segments)","Reference files by path instead of inlining contents","Set maxContextTokens well above the builder's baseline context size","Measure actual child context token totals and tune the limit"],"tags":["subagent","context","tokens","limit"],"backgroundTag":"payload-too-large","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}