paperclipai/paperclip · error · Error

Materialized OpenCode executable did not report ${OPENCODE_V

Error message

Materialized OpenCode executable did not report ${OPENCODE_VERSION}

What it means

As a final smoke test, the script runs the materialized binary with --version (30s timeout) and requires exit status 0 and stdout exactly equal to OPENCODE_VERSION. Any other result means the executable is not the pinned OpenCode version, so it throws.

Source

Thrown at packages/paperclip-runner/scripts/materialize-opencode-binary.mjs:96

  const sourceDigest = sha256(source);
  const targetDigest = sha256(target);
  if (sourceDigest !== targetDigest) {
    throw new Error("Materialized OpenCode executable digest mismatch");
  }
  const targetStat = lstatSync(target);
  const mode = targetStat.mode & 0o777;
  if (!targetStat.isFile() || (mode & 0o111) === 0 || mode & 0o022) {
    throw new Error("Materialized OpenCode executable has unsafe permissions");
  }

  const version = spawnSync(target, ["--version"], {
    encoding: "utf8",
    timeout: 30_000,
    windowsHide: true,
  });
  if (version.status !== 0 || version.stdout.trim() !== OPENCODE_VERSION) {
    throw new Error(
      `Materialized OpenCode executable did not report ${OPENCODE_VERSION}`,
    );
  }
  return { sourceDigest, target, version: OPENCODE_VERSION };
}

const invokedPath = process.argv[1]
  ? pathToFileURL(realpathSync(process.argv[1])).href
  : null;
if (invokedPath === import.meta.url) {
  const result = materializePinnedOpenCodeBinary();
  process.stdout.write(`${JSON.stringify(result)}\n`);
}

View on GitHub (pinned to 01ad858492)

Solutions

  1. Run '<packageRoot>/bin/opencode.exe' --version manually to see actual output or error (missing shared libs, exec format) and fix accordingly.
  2. Align OPENCODE_VERSION in materialize-opencode-binary.mjs with the installed opencode-ai package version (upgrade the dependency or adjust the constant together).
  3. If the --version output format changed, adjust the comparison to match the new format while still pinning the version.
  4. Inspect version.error/version.stderr for ENOEXEC/ENOENT/timeout details when status is non-zero.

Example fix

// before
const OPENCODE_VERSION = "1.1.0"; // but package.json says 1.2.0
// after
const OPENCODE_VERSION = "1.2.0"; // matches installed opencode-ai@1.2.0
Defensive patterns

Strategy: validation

Validate before calling

const out = execSync(`${join(pkgRoot, 'bin', 'opencode.exe')} --version`, { encoding: 'utf8' }).trim();
if (out !== OPENCODE_VERSION) throw new Error(`version probe: got ${out}, want ${OPENCODE_VERSION}`);

Try / catch

try {
  materializePinnedOpenCodeBinary();
} catch (err) {
  if (err.message.includes('did not report')) {
    const actual = spawnSync(target, ['--version'], { encoding: 'utf8' });
    console.error('status:', actual.status, 'stderr:', actual.stderr, 'stdout:', actual.stdout);
  }
  throw err;
}

Prevention

When it happens

Trigger: spawnSync of the target returns non-zero status (binary won't execute — wrong arch, missing loader, corrupted file) or its --version stdout does not exactly equal the pinned version string.

Common situations: A glibc/loader mismatch making the binary fail to start; OPENCODE_VERSION updated but the dependency not upgraded (or vice versa); the --version output format changed upstream; the 30s timeout killed the process.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/19ef5512a92c01ba. Report an issue: GitHub.