JuliusBrussee/caveman · error
cave_subagent_input_limit
cave_subagent_input_limit
Error message
cave_subagent_input_limit
What it means
A subagent task string longer than the tool runtime's maxInputChars cap throws cave_subagent_input_limit. The check runs before admission and budgeting, so an oversized prompt is rejected at zero cost.
Source
Thrown at packages/agent/src/runtime.ts:3872
async function executeSubagent(
toolDefinition: ToolDefinition,
params: unknown,
signal: AbortSignal | undefined,
parentOptions: InternalRunOptions,
usage: NestedUsage,
executionContext: InternalExecutionContext,
parentMeter: BudgetMeter | undefined,
parentDeadlineAt: number | undefined,
): Promise<unknown> {
const runtime = toolDefinition.runtime;
if (runtime?.kind !== "subagent") throw new Error("cave_subagent_runtime_missing");
if (params === null || typeof params !== "object" || Array.isArray(params) ||
typeof (params as { task?: unknown }).task !== "string") {
throw new Error("cave_subagent_arguments_invalid");
}
const task = (params as { task: string }).task;
if (task.length > runtime.maxInputChars) throw new Error("cave_subagent_input_limit");
const calls = usage.calls.get(toolDefinition.name) ?? 0;
if (calls >= runtime.maxCalls) throw new Error("cave_subagent_call_budget");
// Reserve synchronously before any await so parallel Pi tool dispatch cannot
// pass the same maxCalls check twice.
usage.calls.set(toolDefinition.name, calls + 1);
const depth = executionContext.depth;
const depthLimit = Math.min(
parentOptions.maxSubagentDepth ?? DEFAULT_SUBAGENT_DEPTH_LIMIT,
ABSOLUTE_SUBAGENT_DEPTH_LIMIT,
);
if (depth + 1 > depthLimit) throw new Error("cave_subagent_depth_limit");
// The wallet is carved here, still synchronously, for the same reason: two
// subagents dispatched in one turn must not both be funded out of the same
// remaining budget.
const walletAmount = parentMeter === undefined
? undefined
: parentMeter.denomination === "usd" ? runtime.maxCostUsd : runtime.maxTokens;
if (parentMeter !== undefined && walletAmount === undefined) {View on GitHub (pinned to 766dce6b13)
Solutions
- Pass references (file paths, URLs, retrieval handles) instead of inlining content into task
- Shorten or summarize the task before dispatch
- Raise runtime.maxInputChars on the subagent tool definition if the budget allows
Example fix
// before
task: `Summarize this file:\n${await readFile("big.md", "utf8")}`
// after
task: "Read big.md in this repo and summarize it." Defensive patterns
Strategy: validation
Validate before calling
const MAX = tool.runtime.maxInputChars;
if (task.length > MAX) {
throw new Error(`task is ${task.length} chars (max ${MAX}) — pass file paths or references, not content`);
} Prevention
- Always delegate by reference (paths, URLs, handles) instead of pasting content
- Trim or summarize long task text before dispatch
- Set maxInputChars to match what your prompts actually produce, then enforce it
When it happens
Trigger: Inlining an entire document, codebase excerpt, or accumulated transcript into the task field; the model echoing large context into the subagent prompt; task.length exceeding runtime.maxInputChars.
Common situations: Delegating "summarize this file" by pasting the file instead of passing a path; tasks built by concatenating prior tool outputs; maxInputChars set low for cost control.
Related errors
- cave_claude_subagent_bridge_unavailable
- cave_subagent_invocation_limit_invalid
- cave_subagent_concurrency_limit_invalid
- cave_subagent_depth_limit_invalid
- cave_nested_usage_incomplete
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/1ff3d3f80b6e4f91.
Report an issue: GitHub.