JuliusBrussee/caveman · error

cave_subagent_input_limit

cave_subagent_input_limit

Error message

cave_subagent_input_limit

What it means

The runtime caps the character length of the task prompt handed to a subagent at runtime.maxInputChars. A task string longer than this configured limit throws cave_subagent_input_limit, protecting the child agent's context window and cost from oversized inputs.

Solutions

  1. Shorten the task: reference files/paths by name instead of embedding their contents
  2. Increase runtime.maxInputChars in the subagent runtime configuration if large inputs are legitimate
  3. Split the work into multiple smaller subagent tasks
  4. Pre-truncate or summarize the input before dispatching

Example fix

// before
dispatchSubagent({ task: hugeDocument });
// after
dispatchSubagent({ task: "Summarize the file at " + path + " (read it yourself)" });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof task !== "string" || task.length > subagentRuntime.maxInputChars) {
  task = summarizeOrTruncate(task, subagentRuntime.maxInputChars);
}

Try / catch

try {
  await dispatchSubagent({ task });
} catch (e) {
  if (e.message === "cave_subagent_input_limit") {
    await dispatchSubagent({ task: task.slice(0, maxInputChars - 1) });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling a subagent tool where typeof params.task === "string" but task.length > runtime.maxInputChars — e.g. pasting a large document as the task.

Common situations: Asking a subagent to process a big file's contents inline instead of by path; configured maxInputChars too low for the workflow; model echoing huge prior output back as the task text.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/1ff3d3f80b6e4f91. Report an issue: GitHub.

Appendix: 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 3ee70a1026)