{"record":{"id":"c22d8e6b4b56dd0c","repo":"JuliusBrussee/caveman","slug":"cave-subagent-depth-limit-invalid","errorCode":"cave_subagent_depth_limit_invalid","errorMessage":"cave_subagent_depth_limit_invalid","messagePattern":"cave_subagent_depth_limit_invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":1090,"sourceCode":"  // Budget shape is settled before anything else happens: an ambiguous or\n  // unbounded budget must fail at run() start, not after the first dollar.\n  // maxCostUsd and budget are two different contracts for the same money —\n  // one terminates with an error, the other returns a planned partial result —\n  // so carrying both would leave the run's own stop semantics undecided.\n  if (options.budget !== undefined && options.maxCostUsd !== undefined) {\n    throw new Error(\"cave_budget_conflicting_cap\");\n  }\n  const budgetMeter = executionContext.budgetMeter ?? (options.budget === undefined\n    ? undefined\n    : new BudgetMeter(normalizeRunBudget(options.budget)));\n  if (options.deadlineMs !== undefined &&\n      (!Number.isSafeInteger(options.deadlineMs) || options.deadlineMs <= 0)) {\n    throw new Error(\"cave_run_deadline_invalid\");\n  }\n  if (options.maxSubagentDepth !== undefined &&\n      (!Number.isSafeInteger(options.maxSubagentDepth) || options.maxSubagentDepth <= 0 ||\n        options.maxSubagentDepth > ABSOLUTE_SUBAGENT_DEPTH_LIMIT)) {\n    throw new Error(\"cave_subagent_depth_limit_invalid\");\n  }\n  const deadlineAt = executionContext.deadlineAt ?? (options.deadlineMs === undefined\n    ? undefined\n    : performance.now() + options.deadlineMs);\n  // A controller with nothing to release would be a silent no-op at the\n  // checkpoint that expected it to matter.\n  if (options.budgetController !== undefined && budgetMeter === undefined) {\n    throw new Error(\"cave_budget_controller_without_budget\");\n  }\n  const breakers = options.breakers === undefined\n    ? undefined\n    : new BreakerState(normalizeRunBreakers(options.breakers, budgetMeter !== undefined));\n  const efficiencyPlan = options.lockedBuild?.selected_plan ?? options.candidatePlan;\n  const buildIdentity = options.lockedBuild === undefined\n    ? undefined\n    : {\n      buildSha256: options.lockedBuild.build_sha256,\n      planSha256: options.lockedBuild.plan_sha256,","sourceCodeStart":1072,"sourceCodeEnd":1108,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/runtime.ts#L1072-L1108","documentation":"Thrown at run start when RunOptions.maxSubagentDepth is present but invalid: it must be a safe integer, strictly positive, and at most ABSOLUTE_SUBAGENT_DEPTH_LIMIT (8). Depth defaults to 2; a zero, negative, fractional, or >8 value is rejected before any provider call.","triggerScenarios":"Setting maxSubagentDepth: 0 (trying to forbid nesting), a non-integer, or a value like 10 that exceeds the hard limit of 8.","commonSituations":"Assuming deeper recursion is fine and configuring 10 levels; passing a depth derived from config that defaults to 0; trying to express 'no subagents' via depth 0.","solutions":["Use a value in 1..8, e.g. maxSubagentDepth: 3, or omit it for the default of 2","To prevent subagents entirely, remove subagent tools from the definition (depth 0 is not expressible)","Clamp config-driven values: Math.min(8, Math.max(1, Math.floor(d)))"],"exampleFix":"// before\nawait agent.run(input, { maxSubagentDepth: 12 });\n\n// after\nawait agent.run(input, { maxSubagentDepth: Math.min(8, 12) }); // or 8 max","handlingStrategy":"validation","validationCode":"const depth = Math.min(8, Math.max(1, Math.floor(config.depth ?? 2)));\nawait agent.run(input, { maxSubagentDepth: depth });","typeGuard":"const isValidDepth = (v: unknown): v is number =>\n  typeof v === \"number\" && Number.isSafeInteger(v) && v > 0 && v <= 8;","tryCatchPattern":null,"preventionTips":["Remember the absolute depth limit is 8 and the default is 2","Forbid subagents by removing subagent tools, not by depth 0","Validate depth in the same place you validate other run-option integers"],"tags":["subagents","validation","run-options"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}