JuliusBrussee/caveman · error

cave_subagent_arguments_invalid

cave_subagent_arguments_invalid

Error message

cave_subagent_arguments_invalid

What it means

Before running a subagent, the runtime validates that params is a non-null, non-array object whose task property is a string. Any malformed arguments — null params, an array, a non-object, or a missing/non-string task — throw cave_subagent_arguments_invalid. This is strict input validation at the subagent tool boundary.

Solutions

  1. Pass arguments as a plain object with a string task field: { task: "..." }
  2. Validate/parse tool arguments against the tool's input schema before dispatch
  3. Coerce non-string task values to string upstream if the producer cannot be fixed
  4. Inspect the raw tool_call arguments JSON for wrapping/shape mistakes

Example fix

// before
dispatchSubagent("summarize the repo");
// after
dispatchSubagent({ task: "summarize the repo" });
Defensive patterns

Strategy: validation

Validate before calling

function isValidSubagentParams(params) {
  return params !== null && typeof params === "object" && !Array.isArray(params)
    && typeof params.task === "string";
}

Type guard

function hasStringTask(p) {
  return typeof p === "object" && p !== null && !Array.isArray(p)
    && typeof p.task === "string";
}

Try / catch

try {
  await dispatchSubagent(params);
} catch (e) {
  if (e.message === "cave_subagent_arguments_invalid") {
    // fall back to a wrapped form
    await dispatchSubagent({ task: String(rawArg) });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the subagent tool with params = null, params = [], params = "task text" (string not object), or params = {} / { task: 42 } where task is absent or not a string.

Common situations: Model emitting malformed tool arguments that were not schema-validated; caller passing the task text directly instead of wrapping it in { task: ... }; JSON deserialization producing an array; optional task field dropped by an upstream serializer.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at packages/agent/src/runtime.ts:3869

    parentSpanId: parent.spanId,
  });
}

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

View on GitHub (pinned to 3ee70a1026)