JuliusBrussee/caveman · error · Error

cave_harness_upstream_version_mismatch

Error message

cave_harness_upstream_version_mismatch

What it means

The Claude Agent SDK stream emitted an init message whose claude_code_version does not equal the framework's exact pin (CLAUDE_CODE_VERSION, currently "2.1.220" in runtime-identity.ts). The framework exact-pins the upstream harness so tool-calling semantics and message shapes stay reproducible; a drifted CLI breaks that contract. The check fires on the first SDK message, before any model call, so a mismatch costs zero tokens. It is thrown from inside the message loop and surfaces after the finally block closes the query.

Source

Thrown at packages/agent/src/claude-runtime.ts:247

    };

    const startedAt = performance.now();
    const query = (options.queryFn ?? claudeQuery)({ prompt: input, options: sdkOptions });
    let initVersion: string | undefined;
    let assistantModel: string | undefined;
    let credentialRegime: ClaudeCredentialRegime = "unknown";
    let result: SDKResultMessage | undefined;
    const toolCalls: string[] = [];
    try {
      for await (const message of query) {
        if (message.type === "system" && message.subtype === "init") {
          initVersion = message.claude_code_version;
          // The exact-pin is enforced at the FIRST message the SDK emits, before
          // it drives any model call, so a version mismatch costs nothing rather
          // than being caught only after the whole run has drained and spent
          // `finally` closes the query.
          if (initVersion !== CLAUDE_CODE_VERSION) {
            throw new Error("cave_harness_upstream_version_mismatch");
          }
          credentialRegime = claudeCredentialRegime(message.apiKeySource);
          // apiKeySource is emitted on init before the SDK drives a model call.
          // It is the credential the SDK actually selected, unlike ambient env
          // presence. A subscription or unknown regime cannot authorize a USD
          // cap because no per-token dollar charge is proven.
          if (options.maxBudgetUsd !== undefined && credentialRegime !== "metered") {
            throw new Error("cave_budget_denomination_unavailable");
          }
          assistantModel ??= message.model;
        }
        if (message.type === "assistant") {
          assistantModel = message.message.model;
          for (const block of message.message.content) {
            if (block.type === "tool_use") toolCalls.push(unprefixClaudeTool(block.name));
          }
        }
        if (message.type === "result") result = message;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Install the exact pinned version: npm i -g @anthropic-ai/claude-code@2.1.220 (or pin it in devDependencies) and confirm `claude --version`.
  2. Check which CLI the SDK resolves (PATH, CLAUDE_CODE_ENTRYPOINT, or the path option passed to the SDK) and point it at the 2.1.220 install.
  3. If the framework itself is outdated relative to the CLI, upgrade the caveman agent package so its CLAUDE_CODE_VERSION pin matches the CLI you must run.
  4. Verify in CI by asserting `claude --version` equals the value exported from runtime-identity.ts before running builds.

Example fix

// before: ambient CLI resolution, version can drift
const query = queryFn({ ...options });

// after: pin the executable the SDK launches
const query = queryFn({
  ...options,
  pathToClaudeCodeExecutable: "/opt/caveman/claude-2.1.220/claude",
});
Defensive patterns

Strategy: validation

Validate before calling

import { execFileSync } from "node:child_process";
import { CLAUDE_CODE_VERSION } from "@caveman/agent"; // or read runtime-identity
function assertClaudeVersion(pathToClaude = "claude"): void {
  const out = execFileSync(pathToClaude, ["--version"], { encoding: "utf8" }).trim();
  if (!out.includes(CLAUDE_CODE_VERSION)) {
    throw new Error(`CLI ${out} != pinned ${CLAUDE_CODE_VERSION}; install @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}`);
  }
}

Try / catch

try {
  await run(options);
} catch (error) {
  if (error instanceof Error && error.message === "cave_harness_upstream_version_mismatch") {
    // environment defect, not transient: fix the CLI pin before retrying
    throw new Error(`Claude CLI must be ${CLAUDE_CODE_VERSION}; see caveman-agent doctor`);
  }
  throw error;
}

Prevention

When it happens

Trigger: Running an agent whose resolved `claude` CLI executable reports a version other than 2.1.220 on its init system message. Typical causes: a locally installed @anthropic-ai/claude-code of a different version resolved by PATH, an updated global CLI after a framework upgrade (or vice versa), or a PATH option/env pointing at a pinned SDK install that drifted.

Common situations: Upgrading the caveman framework without reinstalling its pinned Claude Code CLI (or the reverse), CI images caching an older CLI, nvm/PATH resolution picking a user-global claude binary, or a teammate's lockfile-less install resolving a newer @anthropic-ai/claude-code.

Related errors


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