can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: CFDATA block ${block} checksum mismatch
Error message
Invalid CAB archive: CFDATA block ${block} checksum mismatch What it means
Thrown by CabFolder.#decode when a CFDATA block's optional 32-bit checksum is present (non-zero) but does not match the XOR checksum computed over the block header (from offset+4 to payload start) and the compressed payload. The CAB format uses this checksum to detect bit-level corruption; a mismatch means the bytes on disk differ from what the cabinet writer produced.
Source
Thrown at packages/utils/src/ar/cab.ts:162
for (let block = 0; block < description.blockCount; block++) {
if (position + DATA_BLOCK_SIZE + this.#dataReserveSize > bytes.byteLength) {
throw new ArchiveError("Invalid CAB archive: truncated CFDATA header");
}
const compressed = readUInt16LE(bytes, position + 4);
const uncompressed = readUInt16LE(bytes, position + 6);
if (uncompressed === 0) throw new ArchiveError("Unsupported multi-volume CAB archive: split CFDATA block");
if (uncompressed > MAX_DATA_OUTPUT) {
throw new ArchiveError(`Invalid CAB archive: CFDATA expands to ${uncompressed} bytes (maximum 32768)`);
}
const payloadStart = position + DATA_BLOCK_SIZE + this.#dataReserveSize;
const payloadEnd = payloadStart + compressed;
if (payloadEnd > bytes.byteLength) throw new ArchiveError("Invalid CAB archive: truncated CFDATA payload");
const expectedChecksum = readUInt32LE(bytes, position);
if (expectedChecksum !== 0) {
const payloadChecksum = cabChecksum(bytes.subarray(payloadStart, payloadEnd));
const actualChecksum = cabChecksum(bytes.subarray(position + 4, payloadStart), payloadChecksum);
if (actualChecksum !== expectedChecksum) {
throw new ArchiveError(`Invalid CAB archive: CFDATA block ${block} checksum mismatch`);
}
}
outputSize += uncompressed;
assertInMemorySize(outputSize, this.#limits);
position = payloadEnd;
}
if (outputSize < description.requiredSize) {
throw new ArchiveError("Invalid CAB archive: folder data is shorter than its file table declares");
}
const output = new Uint8Array(outputSize);
const lzx = description.method === 3 ? new LzxDecoder(description.parameter) : undefined;
position = 0;
let outputPosition = 0;
for (let block = 0; block < description.blockCount; block++) {
const compressed = readUInt16LE(bytes, position + 4);
const uncompressed = readUInt16LE(bytes, position + 6);
const payloadStart = position + DATA_BLOCK_SIZE + this.#dataReserveSize;View on GitHub (pinned to 9690622007)
Solutions
- Re-obtain the archive from its original source and compare checksums
- Test with `cabextract -t file.cab` to confirm corruption is in the file, not the reader
- If you produce cabinets yourself, verify your writer computes the XOR checksum per the CAB spec (or stores 0 to skip checking)
- If you must salvage data, use a repair-oriented extractor that skips bad blocks, accepting partial output
Example fix
// before
await extractCab(untrustedPath, dest);
// after
const ok = await Bun.$`cabextract -t ${untrustedPath}`.quiet().nothrow();
if (!ok.exitCode) throw new Error(`archive corrupt, refusing extraction: ${untrustedPath}`);
await extractCab(untrustedPath, dest); Defensive patterns
Strategy: validation
Validate before calling
const bytes = new Uint8Array(await Bun.file(path).arrayBuffer());
if (!sniffCab(bytes.subarray(0, 4))) throw new Error('not a CAB file');
// content integrity can only be checked by the reader; pre-verify whole-file hash instead
if (await sha256(path) !== expectedHash) throw new Error('file hash mismatch — corrupted or modified'); Try / catch
try {
await readCab(source, opts);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('checksum mismatch'))
logger.error('CAB block checksum failed; archive is corrupt', { path: archivePath });
throw err;
} Prevention
- Store and compare whole-file hashes (sha256) for archived .cab artifacts
- Keep archives on media/paths where they cannot be modified in place
- Fail fast: treat checksum failure as corruption, never attempt partial extraction
When it happens
Trigger: readCab() indexed a cabinet whose stored cfchecksum at the block start differs from cabChecksum(bytes[position+4..payloadStart], cabChecksum(payload)); any single-byte flip in header or payload of a checksummed block triggers it.
Common situations: Bit rot on old storage media; archives corrupted during transfer or by a faulty disk; files modified after creation; DOS/Windows-era cabinets with pre-existing damage.
Related errors
- Invalid CAB archive: truncated CFDATA header
- Invalid CAB archive: truncated CFDATA payload
- Invalid CAB archive: folder data is shorter than its file ta
- Invalid CAB archive: MSZIP block is missing its CK signature
- Invalid CAB archive: empty LZX Huffman tree
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/9e7de185d58ad864.
Report an issue: GitHub.