JuliusBrussee/caveman · error · Error

cave_${harness}_upstream_version_mismatch

cave_${harness}_upstream_version_mismatch

Error message

cave_${harness}_upstream_version_mismatch

What it means

The installed harness version resolves and matches the adapter's pin, but the `upstreamVersion` the caller supplied in the harness identity does not equal the installed version. The pin chain requires lock, plan, installed package, and claimed identity to agree; a claim alone cannot authorize execution. This almost always means the identity object was built from a stale or hardcoded version string instead of the live runtime.

Source

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

function assertSupportedUpstream(
  identity: HarnessAdapterIdentity,
  expected: string,
  harness: string,
  pkg: string,
): void {
  // The pin is enforced against the INSTALLED version, and the caller's claimed
  // upstreamVersion must match what is actually installed — a claim alone can no
  // longer authorize execution.
  const installed = installedPackageVersion(pkg);
  if (installed === undefined) {
    throw new Error(`cave_${harness}_upstream_version_unresolvable`);
  }
  if (installed !== expected) {
    throw new Error(`cave_${harness}_upstream_version_unsupported`);
  }
  if (identity.upstreamVersion !== installed) {
    throw new Error(`cave_${harness}_upstream_version_mismatch`);
  }
}

function canonicalRecord(value: Readonly<Record<string, unknown>>): Readonly<Record<string, unknown>> {
  let encoded: string;
  try {
    encoded = stableStringify(value);
  } catch {
    throw new Error("cave_harness_wire_contract_invalid");
  }
  const decoded = JSON.parse(encoded) as unknown;
  if (!isRecord(decoded)) throw new Error("cave_harness_wire_contract_invalid");
  return decoded;
}

function deepFreeze<T>(value: T): T {
  if (value !== null && typeof value === "object") {
    Object.freeze(value);

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Update the `upstreamVersion` in the identity you pass to match the installed version reported in the error.
  2. Better: derive the identity's `upstreamVersion` at runtime from the installed package (or obtain the identity from the framework) instead of hardcoding it.
  3. After any dependency change, regenerate lock/plan artifacts that embed the upstream version.

Example fix

// before
const identity = { upstreamVersion: "7.0.40", /* ... */ }; // installed is 7.0.43

// after
const identity = { upstreamVersion: "7.0.43", /* ... */ };
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from "node:fs";
function installedVersion(pkg: string): string {
  return JSON.parse(
    readFileSync(fileURLToPath(import.meta.resolve(`${pkg}/package.json`)), "utf8"),
  ).version as string;
}
// derive, never hardcode:
const identity = { upstreamVersion: installedVersion("ai"), /* ... */ };

Try / catch

try {
  await adapter.run(request);
} catch (err) {
  if (err instanceof Error && err.message.endsWith("_upstream_version_mismatch")) {
    // rebuild identity from the installed version and retry once
  }
}

Prevention

When it happens

Trigger: Passing a `HarnessAdapterIdentity` with `upstreamVersion: "7.0.40"` while 7.0.43 is installed; caching an identity across an `npm install` that bumped the pinned-but-then-reinstalled package; building identity from a constant instead of reading the installed package version.

Common situations: Hardcoding the upstream version in app code and forgetting to update it after a reinstall; reusing a serialized identity from a previous session/lock file; CI image rebuilt with a patched harness version while the app config still names the old one.

Related errors


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