{"record":{"id":"19ef5512a92c01ba","repo":"paperclipai/paperclip","slug":"materialized-opencode-executable-did-not-report","errorCode":null,"errorMessage":"Materialized OpenCode executable did not report ${OPENCODE_VERSION}","messagePattern":"Materialized OpenCode executable did not report (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/scripts/materialize-opencode-binary.mjs","lineNumber":96,"sourceCode":"\n  const sourceDigest = sha256(source);\n  const targetDigest = sha256(target);\n  if (sourceDigest !== targetDigest) {\n    throw new Error(\"Materialized OpenCode executable digest mismatch\");\n  }\n  const targetStat = lstatSync(target);\n  const mode = targetStat.mode & 0o777;\n  if (!targetStat.isFile() || (mode & 0o111) === 0 || mode & 0o022) {\n    throw new Error(\"Materialized OpenCode executable has unsafe permissions\");\n  }\n\n  const version = spawnSync(target, [\"--version\"], {\n    encoding: \"utf8\",\n    timeout: 30_000,\n    windowsHide: true,\n  });\n  if (version.status !== 0 || version.stdout.trim() !== OPENCODE_VERSION) {\n    throw new Error(\n      `Materialized OpenCode executable did not report ${OPENCODE_VERSION}`,\n    );\n  }\n  return { sourceDigest, target, version: OPENCODE_VERSION };\n}\n\nconst invokedPath = process.argv[1]\n  ? pathToFileURL(realpathSync(process.argv[1])).href\n  : null;\nif (invokedPath === import.meta.url) {\n  const result = materializePinnedOpenCodeBinary();\n  process.stdout.write(`${JSON.stringify(result)}\\n`);\n}\n","sourceCodeStart":78,"sourceCodeEnd":110,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/scripts/materialize-opencode-binary.mjs#L78-L110","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run '<packageRoot>/bin/opencode.exe' --version manually to see actual output or error (missing shared libs, exec format) and fix accordingly.","Align OPENCODE_VERSION in materialize-opencode-binary.mjs with the installed opencode-ai package version (upgrade the dependency or adjust the constant together).","If the --version output format changed, adjust the comparison to match the new format while still pinning the version.","Inspect version.error/version.stderr for ENOEXEC/ENOENT/timeout details when status is non-zero."],"exampleFix":"// before\nconst OPENCODE_VERSION = \"1.1.0\"; // but package.json says 1.2.0\n// after\nconst OPENCODE_VERSION = \"1.2.0\"; // matches installed opencode-ai@1.2.0","handlingStrategy":"validation","validationCode":"const out = execSync(`${join(pkgRoot, 'bin', 'opencode.exe')} --version`, { encoding: 'utf8' }).trim();\nif (out !== OPENCODE_VERSION) throw new Error(`version probe: got ${out}, want ${OPENCODE_VERSION}`);","typeGuard":null,"tryCatchPattern":"try {\n  materializePinnedOpenCodeBinary();\n} catch (err) {\n  if (err.message.includes('did not report')) {\n    const actual = spawnSync(target, ['--version'], { encoding: 'utf8' });\n    console.error('status:', actual.status, 'stderr:', actual.stderr, 'stdout:', actual.stdout);\n  }\n  throw err;\n}","preventionTips":["Bump OPENCODE_VERSION and the dependency version in the same commit.","Verify the binary runs on the target OS (matching loader/glibc) before pinning.","Check upstream --version output format changes when upgrading.","Keep the spawn timeout generous enough for cold starts in CI."],"tags":["versioning","verification","binary","spawn"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}