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

  1. Pass references (file paths, URLs, retrieval handles) instead of inlining content into task
  2. Shorten or summarize the task before dispatch
  3. 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

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


AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18). Data as JSON: /api/errors/1ff3d3f80b6e4f91. Report an issue: GitHub.