{"record":{"id":"34ad719f94032c51","repo":"JuliusBrussee/caveman","slug":"caveman-agent-subagent-maxtokens-must-be-a-positi","errorCode":null,"errorMessage":"caveman agent: subagent maxTokens must be a positive integer","messagePattern":"caveman agent: subagent maxTokens must be a positive integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/index.ts","lineNumber":182,"sourceCode":"  maxTokens?: number;\n  maxContextTokens?: number;\n}): ToolDefinition {\n  const maxInputChars = options.maxInputChars ?? 32_768;\n  if (!Number.isSafeInteger(maxInputChars) || maxInputChars <= 0) {\n    throw new Error(\"caveman agent: subagent maxInputChars must be a positive integer\");\n  }\n  const maxCalls = options.maxCalls ?? 1;\n  const maxCostUsd = options.maxCostUsd ?? 1;\n  const maxContextTokens = options.maxContextTokens ?? 128_000;\n  if (!Number.isSafeInteger(maxCalls) || maxCalls <= 0) {\n    throw new Error(\"caveman agent: subagent maxCalls must be a positive integer\");\n  }\n  if (!Number.isFinite(maxCostUsd) || maxCostUsd <= 0) {\n    throw new Error(\"caveman agent: subagent maxCostUsd must be positive\");\n  }\n  if (options.maxTokens !== undefined &&\n      (!Number.isSafeInteger(options.maxTokens) || options.maxTokens <= 0)) {\n    throw new Error(\"caveman agent: subagent maxTokens must be a positive integer\");\n  }\n  if (!Number.isSafeInteger(maxContextTokens) || maxContextTokens <= 0) {\n    throw new Error(\"caveman agent: subagent maxContextTokens must be a positive integer\");\n  }\n  return tool({\n    name: options.name,\n    description: options.description,\n    input: schema.object({ task: schema.string() }),\n    effect: \"read\",\n    result: \"auto\",\n    ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),\n    runtime: {\n      kind: \"subagent\",\n      definition: options.agent,\n      maxInputChars,\n      maxCalls,\n      maxCostUsd,\n      ...(options.maxTokens === undefined ? {} : { maxTokens: options.maxTokens }),","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/index.ts#L164-L200","documentation":"`subagent()` accepts an optional `maxTokens` option limiting per-call model output. When provided, it must be a positive safe integer; undefined skips the check (no limit). The library throws at tool-creation time when a caller passes 0, a negative number, a float, or a non-integer.","triggerScenarios":"Calling `subagent({ maxTokens: 0 })`, `subagent({ maxTokens: -100 })`, `subagent({ maxTokens: 1024.5 })`, `subagent({ maxTokens: NaN })`, or passing a string like `\"4096\"` from config.","commonSituations":"Copying provider maxOutputTokens as a string; computing the value from arithmetic that yields a float; attempting to disable the token cap by setting 0 instead of leaving it undefined.","solutions":["Pass a positive integer, e.g. `subagent({ maxTokens: 4096 })`, or omit the option entirely for no limit.","Coerce string config with `Number.parseInt(raw, 10)` and check `Number.isSafeInteger(v) && v > 0` before passing.","To remove a cap, delete the maxTokens key rather than setting it to 0."],"exampleFix":"// before\nsubagent({ name: \"writer\", maxTokens: cfg.maxTokens ?? 0 })\n// after\nconst maxTokens = cfg.maxTokens === undefined ? undefined : Number.parseInt(cfg.maxTokens, 10);\nsubagent({ name: \"writer\", ...(maxTokens === undefined ? {} : { maxTokens }) })","handlingStrategy":"validation","validationCode":"function normalizeMaxTokens(v) {\n  if (v === undefined) return undefined;\n  const n = typeof v === \"string\" ? Number.parseInt(v, 10) : v;\n  if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`maxTokens must be a positive integer, got ${v}`);\n  return n;\n}\nconst opts = { name: \"writer\" };\nconst mt = normalizeMaxTokens(cfg.maxTokens);\nif (mt !== undefined) opts.maxTokens = mt;\nsubagent(opts);","typeGuard":"const isOptionalPosInt = (v) => v === undefined || (typeof v === \"number\" && Number.isSafeInteger(v) && v > 0);","tryCatchPattern":"try {\n  const t = subagent({ maxTokens: cfg.maxTokens });\n} catch (e) {\n  if (e.message.includes(\"maxTokens must be a positive integer\")) {\n    console.warn(\"Ignoring invalid maxTokens; running without token cap\");\n    return subagent({}); // omit the option entirely\n  }\n  throw e;\n}","preventionTips":["Remember maxTokens is optional — omit it rather than passing 0","Coerce numeric strings from config before passing","Type the option as number | undefined in your config layer so TS catches strings","Test tool construction with both present and absent optional options"],"tags":["configuration","validation","argument-error"],"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"}