can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: truncated CFDATA payload
Error message
Invalid CAB archive: truncated CFDATA payload
What it means
Thrown by CabFolder.#decode when a CFDATA block's declared compressed size extends past the end of the folder's byte range read from the archive. The library validates every data block boundary before decompressing, so a cabinet whose payload region is shorter than the block table claims is rejected instead of producing a partial or garbage extraction.
Source
Thrown at packages/utils/src/ar/cab.ts:156
const compressedSize = description.dataEnd - description.dataStart;
assertInMemorySize(compressedSize, this.#limits);
const bytes = await readExact(this.#source, description.dataStart, description.dataEnd);
let position = 0;
let outputSize = 0;
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;View on GitHub (pinned to 9690622007)
Solutions
- Re-download or re-copy the .cab archive and verify its size/hash against the source
- Verify the archive opens with an independent tool (e.g. `cabextract -t file.cab`) to confirm the file is corrupt, not the library
- If the file comes from your own build pipeline, check the step that produces the cabinet for premature stream close
- Wrap extraction in try-catch on ArchiveError and surface a 'corrupt archive, re-fetch' message to users
Example fix
// before
const data = await Bun.file(downloadPath).arrayBuffer();
await readCab(new Uint8Array(data), opts);
// after
const data = await Bun.file(downloadPath).arrayBuffer();
const expected = await fetchExpectedSize();
if (data.byteLength !== expected) throw new Error(`incomplete download: ${data.byteLength}/${expected}`);
await readCab(new Uint8Array(data), opts); Defensive patterns
Strategy: validation
Validate before calling
const stat = await Bun.file(path).stat();
const expectedSize = await getExpectedSize(path); // from manifest/CDN
if (stat.size !== expectedSize) throw new Error(`truncated archive: ${stat.size} != ${expectedSize}`); Try / catch
try {
await readCab(source, opts);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('truncated CFDATA payload'))
throw new Error('Archive is incomplete or corrupt — re-download it.');
throw err;
} Prevention
- Verify file size/hash against the source before extraction
- Use resumable, checksum-verified downloads for large .cab files
- Test archives with `cabextract -t` before processing
When it happens
Trigger: readCab() indexed a cabinet whose CFFOLDER declared a block whose cbData (compressed size at offset+4) makes payloadEnd exceed the folder's data region; typically the file was truncated mid-download or the folder data ranges were corrupted.
Common situations: Interrupted downloads or uploads of .cab files; partial Git LFS/CDN fetches; archives corrupted in transit; hand-crafted or fuzzed cabinet files; extracting from a network stream that was cut short.
Related errors
- Truncated embedded addon archive entry: ${filename}
- Invalid CAB archive: truncated CFDATA header
- Invalid CAB archive: CFDATA block ${block} checksum mismatch
- Invalid CAB archive: folder data is shorter than its file ta
- Invalid CAB archive: MSZIP block is missing its CK signature
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d39fb3f8e0450016.
Report an issue: GitHub.