oven-sh/bun · error · Error
size mismatch
Error message
size mismatch
What it means
The integrity hash recorded for a package does not match the tarball bytes that were downloaded. Verification happens in ExtractTarball::run before extraction (src/install/extract_tarball.rs:47-58) and while streaming the download (src/install/TarballStream.rs:1121); for GitHub/URL/local tarballs Bun deliberately computes and pins the hash in the lockfile so a compromised server cannot silently swap content (comment at extract_tarball.rs:62-65).
Source
Thrown at bench/copyfile/node.mitata.mjs:15
import { copyFileSync, statSync, writeFileSync } from "node:fs";
import { bench, run } from "../runner.mjs";
function runner(ready) {
for (let size of [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000]) {
const rand = new Int32Array(size);
for (let i = 0; i < size; i++) {
rand[i] = (Math.random() * 1024 * 1024) | 0;
}
const dest = `/tmp/fs-test-copy-file-${((Math.random() * 10000000 + 100) | 0).toString(32)}`;
const src = `/tmp/fs-test-copy-file-${((Math.random() * 10000000 + 100) | 0).toString(32)}`;
writeFileSync(src, Buffer.from(rand.buffer), { encoding: "buffer" });
const { size: fileSize } = statSync(src);
if (fileSize !== rand.byteLength) {
throw new Error("size mismatch");
}
ready(src, dest, new Uint8Array(rand.buffer));
}
}
runner((src, dest, rand) =>
bench(`copyFileSync(${rand.buffer.byteLength} bytes)`, () => {
copyFileSync(src, dest);
// const output = readFileSync(dest).buffer;
// for (let i = 0; i < output.length; i++) {
// if (output[i] !== rand[i]) {
// throw new Error(
// "Files are not equal" + " " + output[i] + " " + rand[i] + " " + i
// );
// }
// }
}),
);View on GitHub (pinned to 8c5296ac45)
Solutions
- Clear the cache and reinstall: `bun pm cache rm && bun install`
- For URL/GitHub tarballs pinned to a branch, re-record the hash: re-run `bun add <url-or-github-spec>` so the lockfile captures the current tarball
- Compare hashes out-of-band: `npm view <pkg> dist.integrity` vs. curl the tarball and compute its sha512
- If tampering is plausible, do NOT bypass the check: pin an exact version/commit and verify the artifact from the official registry
Example fix
// before (package.json): moving ref, hash drifts on every push "ui-kit": "github:acme/ui-kit#main" // after: immutable ref, lockfile hash stays valid "ui-kit": "github:acme/ui-kit#1f0e3d8c2a7b94f6cc4e21c1d7f3a9b8"
Defensive patterns
Strategy: validation
Validate before calling
// Before promoting a URL/git tarball dep, confirm the bytes match what you will pin:
const res = Bun.spawnSync(["npm", "view", "your-pkg", "dist.integrity"], { stdout: "pipe" });
const pinned = Bun.file("bun.lock").text(); // or your recorded hash
console.log("registry integrity:", res.stdout.toString().trim()); Type guard
const isValidSRI = (s) => /^sha(1|256|384|512)-[A-Za-z0-9+/=]+$/.test(s ?? "");
Prevention
- Pin git/URL dependencies to immutable refs (commit SHA or tag), never branches
- Use one registry consistently; do not switch mirrors between installs
- Run CI with --frozen-lockfile so hashes are checked, not recomputed
- Treat an unexpected IntegrityCheckFailed as a possible attack: verify out-of-band instead of deleting the check
When it happens
Trigger: `bun install` with a lockfile whose pinned sha512/sha1 differs from the fetched artifact: registry mirror out of sync for the same version, a corrupted cache entry, a GitHub tarball re-generated for a moving ref (branch/HEAD) while the lockfile pins the old hash, or a yanked-and-republished package.
Common situations: Switching between registry mirrors that serve different bytes; using `github:owner/repo#main` style deps whose tarballs change; CI cache corruption; in rare cases actual supply-chain tampering.
Related errors
- page-cache eviction failed for ${path}; results would be war
- not 200
- Invalid data object: ${JSON.stringify(data)}
- Expected ${receivedCount[0]} to equal ${sentCount}
- not called
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/91d7e8d0f2c153ad.
Report an issue: GitHub.