{"record":{"id":"3807aa3064eab214","repo":"JuliusBrussee/caveman","slug":"cave-harness-upstream-version-mismatch","errorCode":"cave_harness_upstream_version_mismatch","errorMessage":"cave_harness_upstream_version_mismatch","messagePattern":"cave_harness_upstream_version_mismatch","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/adapters.ts","lineNumber":260,"sourceCode":"  session: EveSessionBinding,\n): HarnessAdapter {\n  assertSupportedUpstream(identity, EVE_VERSION, \"eve\", \"eve\");\n  return createHarnessAdapter(\"eve\", identity, {\n    package: \"eve/client\",\n    class: \"ClientSession\",\n    method: \"send.result\",\n    usage: \"step.completed.data.usage\",\n  }, async (request) => {\n    const startedAt = performance.now();\n    const response = await session.send({\n      message: request.prompt,\n      ...(request.signal === undefined ? {} : { signal: request.signal }),\n    });\n    const result = await response.result();\n    if (result.status !== \"completed\") throw new Error(`cave_eve_terminal_${result.status}`);\n    const identity = eveRuntimeIdentity(result.events);\n    if (identity.upstreamVersion !== request.build.harness.upstream_version) {\n      throw new Error(\"cave_harness_upstream_version_mismatch\");\n    }\n    const usage = usageFromEveEvents(result.events, request.plan.reasoning !== \"none\");\n    return harnessExecution({\n      request,\n      text: result.message ?? \"\",\n      provider: identity.provider,\n      model: identity.model,\n      usage,\n      latencyMs: Math.round(performance.now() - startedAt),\n    });\n  });\n}\n\nexport interface MastraAgentBinding {\n  generate(messages: string, options?: {\n    maxProcessorRetries?: number;\n    maxSteps?: number;\n    runId?: string;","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/adapters.ts#L242-L278","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\necho \"\\\"$file_path\\\"\" | caveman-shrink # top-level JSON string\n\n# after\ncat \"$file_path\" | caveman-shrink # file contains {\"tools\":[...]} or [...]","handlingStrategy":"type-guard","validationCode":"var probe any\nif err := json.Unmarshal(input, &probe); err != nil {\n    return fmt.Errorf(\"not valid JSON: %w\", err)\n}\nswitch probe.(type) {\ncase map[string]any, []any:\n    // ok: object or array shape proceeds to tool extraction\ndefault:\n    return fmt.Errorf(\"top-level JSON is %T; expected object or array\", probe)\n}","typeGuard":"func isCatalogShaped(b []byte) bool {\n    var probe any\n    if json.Unmarshal(b, &probe) != nil {\n        return false\n    }\n    switch probe.(type) {\n    case map[string]any, []any:\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["json","parsing","api-contract","input-validation"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}