JuliusBrussee/caveman · error · Error

cave_harness_upstream_version_mismatch

cave_harness_upstream_version_mismatch

Error message

cave_harness_upstream_version_mismatch

What it means

After successfully parsing JSON, extractTools switches on the top-level type: a map (tools/functions/single object), or an array. 'unsupported catalog shape' fires when the parsed document is neither — i.e. top-level JSON is a string, number, boolean, or null. The JSON was syntactically valid but structurally useless for tool extraction.

Source

Thrown at packages/agent/src/adapters.ts:260

  session: EveSessionBinding,
): HarnessAdapter {
  assertSupportedUpstream(identity, EVE_VERSION, "eve", "eve");
  return createHarnessAdapter("eve", identity, {
    package: "eve/client",
    class: "ClientSession",
    method: "send.result",
    usage: "step.completed.data.usage",
  }, async (request) => {
    const startedAt = performance.now();
    const response = await session.send({
      message: request.prompt,
      ...(request.signal === undefined ? {} : { signal: request.signal }),
    });
    const result = await response.result();
    if (result.status !== "completed") throw new Error(`cave_eve_terminal_${result.status}`);
    const identity = eveRuntimeIdentity(result.events);
    if (identity.upstreamVersion !== request.build.harness.upstream_version) {
      throw new Error("cave_harness_upstream_version_mismatch");
    }
    const usage = usageFromEveEvents(result.events, request.plan.reasoning !== "none");
    return harnessExecution({
      request,
      text: result.message ?? "",
      provider: identity.provider,
      model: identity.model,
      usage,
      latencyMs: Math.round(performance.now() - startedAt),
    });
  });
}

export interface MastraAgentBinding {
  generate(messages: string, options?: {
    maxProcessorRetries?: number;
    maxSteps?: number;
    runId?: string;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Inspect what you are actually piping: cat the input through jq type — it must be 'object' or 'array'.
  2. Fix the producer to emit the documented catalog shapes: {"tools":[...]}, {"functions":[...]}, an array, or a single tool object.
  3. For double-encoded JSON, decode once more: jq -c 'fromjson' input.json.

Example fix

# before
echo "\"$file_path\"" | caveman-shrink # top-level JSON string

# after
cat "$file_path" | caveman-shrink # file contains {"tools":[...]} or [...]
Defensive patterns

Strategy: type-guard

Validate before calling

var probe any
if err := json.Unmarshal(input, &probe); err != nil {
    return fmt.Errorf("not valid JSON: %w", err)
}
switch probe.(type) {
case map[string]any, []any:
    // ok: object or array shape proceeds to tool extraction
default:
    return fmt.Errorf("top-level JSON is %T; expected object or array", probe)
}

Type guard

func isCatalogShaped(b []byte) bool {
    var probe any
    if json.Unmarshal(b, &probe) != nil {
        return false
    }
    switch probe.(type) {
    case map[string]any, []any:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Piping a bare JSON string (e.g. "\"ok\"" or a quoted file path), a number, true/false, or null into the tool-catalog shrink path; an MCP API returning a JSON-encoded error string at top level instead of an object.

Common situations: An upstream service returning a JSON scalar as its whole body; echoing the wrong variable ($flag instead of $payload) into the pipe; double-encoded JSON where the outer decode yields a string.

Related errors


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