JuliusBrussee/caveman · warning

${key} is required

Error message

${key} is required

What it means

stringArg() in the CLI's MCP tool layer (packages/cli/src/agent-mcp.ts) throws when a required string argument is absent, not a string, or whitespace-only. It backs tools like caveman_report (report), caveman_trace_get (trace_id), and caveman_experiment_get (action, experiment_id), so the MCP client sees an isError result naming the missing key.

Source

Thrown at packages/cli/src/agent-mcp.ts:410

function metadataOnlyTrace(trace: JSONValue): JSONObject {
  return allowlistedObject(trace, AGENT_TRACE_FIELDS);
}

function metadataOnlySpans(value: JSONValue): JSONObject {
  if (!value || typeof value !== "object" || Array.isArray(value)) return { spans: [], timeline: [] };
  const spans = Array.isArray(value.spans)
    ? value.spans.map((span) => allowlistedObject(span, AGENT_SPAN_FIELDS))
    : [];
  const timeline = Array.isArray(value.timeline)
    ? value.timeline.map((event) => allowlistedObject(event, AGENT_TIMELINE_FIELDS))
    : [];
  return { spans, timeline };
}

function stringArg(args: JSONObject, key: string): string {
  const value = args[key];
  if (typeof value !== "string" || value.trim() === "") throw new Error(`${key} is required`);
  return value;
}

function result(value: JSONValue): ToolResult {
  const structuredContent = value && typeof value === "object" && !Array.isArray(value)
    ? value as JSONObject
    : { value };
  return {
    content: [{ type: "text", text: JSON.stringify(structuredContent) }],
    structuredContent,
  };
}

function errorResult(error: unknown): ToolResult {
  const candidate = error as { message?: unknown; code?: unknown; status?: unknown };
  const structuredContent: JSONObject = {
    error: typeof candidate.code === "string" ? candidate.code : "cave_agent_tool_failed",
    message: typeof candidate.message === "string" ? candidate.message : "Caveman tool failed.",

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Supply the named argument as a non-empty string (e.g. {"trace_id": "abc123"}).
  2. Stringify numeric ids before calling: String(experimentId).
  3. Define the argument as required in your MCP client's tool schema so the model cannot omit it.

Example fix

// before
callTool("caveman_trace_get", {})

// after
callTool("caveman_trace_get", { trace_id: "01J8Z..." })
Defensive patterns

Strategy: validation

Validate before calling

function requireStringArg(args: Record<string, unknown>, key: string): string {
  const v = args[key];
  if (typeof v !== "string" || v.trim() === "") throw new Error(`${key} is required`);
  return v;
}
// before calling caveman_trace_get / caveman_report / caveman_experiment_get:
requireStringArg(args, "trace_id");

Type guard

function isNonEmptyString(v: unknown): v is string {
  return typeof v === "string" && v.trim() !== "";
}

Try / catch

try { await client.callTool("caveman_trace_get", args); } catch (e) { if (e instanceof Error && /is required$/.test(e.message)) { /* prompt for the missing arg, do not retry unchanged */ } throw e; }

Prevention

When it happens

Trigger: Calling caveman_trace_get without trace_id; passing trace_id as a number; sending "" or " " for report/action/experiment_id; an LLM omitting the argument in its tool-call JSON.

Common situations: A model-generated tool call drops a required field; a client sends numeric ids (e.g. 12345 instead of "12345"); copy-paste payloads trimmed to placeholders.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/cd230833f43c8cf6. Report an issue: GitHub.