{"record":{"id":"67a084271e04f100","repo":"JuliusBrussee/caveman","slug":"cave-subagent-invocation-limit-invalid","errorCode":"cave_subagent_invocation_limit_invalid","errorMessage":"cave_subagent_invocation_limit_invalid","messagePattern":"cave_subagent_invocation_limit_invalid","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":1062,"sourceCode":"      controller.abort(error);\n      return inner.throw(error);\n    },\n    [Symbol.asyncIterator]() {\n      return this;\n    },\n  } as AsyncGenerator<CavemanRunEvent>;\n}\n\nasync function* streamAgentInternal(\n  definition: AgentDefinition,\n  input: string,\n  options: InternalRunOptions,\n  executionContext: InternalExecutionContext,\n): AsyncGenerator<CavemanRunEvent> {\n  if (options.maxSubagentInvocations !== undefined &&\n      (!Number.isSafeInteger(options.maxSubagentInvocations) || options.maxSubagentInvocations <= 0 ||\n        options.maxSubagentInvocations > ABSOLUTE_SUBAGENT_INVOCATION_LIMIT)) {\n    throw new Error(\"cave_subagent_invocation_limit_invalid\");\n  }\n  if (options.maxConcurrentSubagents !== undefined &&\n      (!Number.isSafeInteger(options.maxConcurrentSubagents) || options.maxConcurrentSubagents <= 0 ||\n        options.maxConcurrentSubagents > ABSOLUTE_SUBAGENT_INVOCATION_LIMIT)) {\n    throw new Error(\"cave_subagent_concurrency_limit_invalid\");\n  }\n  if (options.lockedBuild !== undefined && options.candidatePlan !== undefined) {\n    throw new Error(\"cave_execution_authorization_ambiguous\");\n  }\n  // 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","sourceCodeStart":1044,"sourceCodeEnd":1080,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/runtime.ts#L1044-L1080","documentation":"RunOptions.maxSubagentInvocations caps total subagent admissions across the whole run tree. streamAgentInternal validates it at run start: it must be a safe integer > 0 and at most ABSOLUTE_SUBAGENT_INVOCATION_LIMIT (1,000,000). Any other value throws this error before any model or tool traffic.","triggerScenarios":"Calling runAgent/streamAgent with options.maxSubagentInvocations set to 0, a negative number, a non-integer (e.g. 1.5), NaN/Infinity, or a number above 1,000,000.","commonSituations":"Config values read from environment variables or JSON as strings/floats; computing the cap from a formula that yields 0 or fractional values; typos like 10000000 (one zero too many) exceeding the absolute cap.","solutions":["Pass a positive safe integer between 1 and 1,000,000 for maxSubagentInvocations.","Coerce config input first: Number.isSafeInteger(v) check, and Math.floor/parseInt for strings from env or CLI.","Omit the option entirely if you do not need a tree-wide invocation cap (unset preserves default behavior)."],"exampleFix":"// before\nawait runAgent(def, input, { maxSubagentInvocations: Number(process.env.MAX_SUBAGENTS) });\n// after\nconst n = Number.parseInt(process.env.MAX_SUBAGENTS ?? \"\", 10);\nawait runAgent(def, input, Number.isSafeInteger(n) && n > 0 && n <= 1_000_000\n  ? { maxSubagentInvocations: n }\n  : {});","handlingStrategy":"validation","validationCode":"function isValidSubagentInvocationLimit(v) {\n  return v === undefined || (Number.isSafeInteger(v) && v > 0 && v <= 1_000_000);\n}","typeGuard":"function hasValidMaxSubagentInvocations(o) {\n  return o.maxSubagentInvocations === undefined ||\n    (Number.isSafeInteger(o.maxSubagentInvocations) && o.maxSubagentInvocations > 0);\n}","tryCatchPattern":"try {\n  await runAgent(def, input, opts);\n} catch (err) {\n  if (err.message === \"cave_subagent_invocation_limit_invalid\") {\n    delete opts.maxSubagentInvocations; // fall back to default behavior\n  } else throw err;\n}","preventionTips":["Parse numeric options with Number.parseInt and Number.isSafeInteger before passing.","Never trust raw env/JSON values as numeric options.","Clamp generated caps to [1, 1_000_000]."],"tags":["agent-runtime","validation","options"],"backgroundTag":"invalid-argument-value","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"}