paperclipai/paperclip · critical · Error
Materialized OpenCode executable digest mismatch
Error message
Materialized OpenCode executable digest mismatch
What it means
After hard-linking and chmod 0o755, the script recomputes SHA-256 digests of source and target and requires them to be identical, proving the target holds the pinned bytes. A mismatch means the materialized executable is not the verified pinned build, so it throws.
Source
Thrown at packages/paperclip-runner/scripts/materialize-opencode-binary.mjs:82
throw new Error("OpenCode target executable is not a regular file");
}
unlinkSync(target);
}
try {
linkSync(source, target);
} catch (error) {
const code = error?.code;
if (!new Set(["EACCES", "EMLINK", "EPERM", "EXDEV"]).has(code)) {
throw error;
}
copyFileSync(source, target);
}
chmodSync(target, 0o755);
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 };View on GitHub (pinned to 01ad858492)
Solutions
- Delete the target (rm <packageRoot>/bin/opencode.exe) and re-run materializePinnedOpenCodeBinary on a local filesystem.
- Verify the source binary itself is intact against the upstream pinned release digest; reinstall the baseline package if mutated.
- Run outside volumes/containers that break hard links (check with 'stat -c %i' that source and target share an inode).
- Exclude the package bin directory from antivirus/on-access scanning during build.
Example fix
# before $ sha256sum bin/opencode.exe # differs from baseline bin/opencode # after $ rm bin/opencode.exe && node scripts/materialize-opencode-binary.mjs $ sha256sum bin/opencode.exe # matches source digest
Defensive patterns
Strategy: validation
Validate before calling
import { createHash } from 'node:crypto';
import { readFileSync } from 'node:fs';
const digest = (p) => createHash('sha256').update(readFileSync(p)).digest('hex');
if (digest(source) !== digest(target)) throw new Error('pre-check: materialized binary digest mismatch'); Try / catch
try {
materializePinnedOpenCodeBinary();
} catch (err) {
if (err.message === 'Materialized OpenCode executable digest mismatch') {
// treat as tampering/corruption: rebuild from a clean install
execSync('pnpm install --force');
materializePinnedOpenCodeBinary();
} else throw err;
} Prevention
- Verify the upstream pinned binary digest against the release checksum before materializing.
- Build on local filesystems, not network/overlay mounts that break hard links.
- Exclude package bin dirs from antivirus on-access rewriting.
- Fail closed: never run a binary whose digest check failed.
When it happens
Trigger: The target file's digest differs from the source after linking — e.g. the target was modified between link and digest, a stale different binary is at the target, or the filesystem broke hard-link semantics.
Common situations: Antivirus or build tooling rewrote the freshly linked binary; building inside a container/volume where hard links degrade to copies; a race where another process replaced opencode.exe concurrently.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- runnerd digest mismatch: expected ${request.runnerd.sha256},
- Public viewer asset differs from trusted build: ${file}
- ACPX ${agent} runtime executable digest mismatch
- ACPX snapshot manifest digest mismatch
- ACPX private snapshot digest mismatch
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/ebb3ed3472e104f4.
Report an issue: GitHub.