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
- Inspect what you are actually piping: cat the input through jq type — it must be 'object' or 'array'.
- Fix the producer to emit the documented catalog shapes: {"tools":[...]}, {"functions":[...]}, an array, or a single tool object.
- 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
- Check the top-level type with jq type before piping; require 'object' or 'array'.
- Pin your catalog producer to the documented shapes and add a schema test.
- Beware double-encoded JSON: run jq -c 'fromjson' when the API returns JSON-in-a-string.
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
- cave_eve_terminal_${result.status}
- cave_mastra_max_steps_invalid
- cave_claude_header_invalid
- caveman agent: invalid .caveman/provider.json
- registry output has no valid registry_sha256
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/3807aa3064eab214.
Report an issue: GitHub.