can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: truncated data
Error message
Invalid CAB archive: truncated data
What it means
readExact verifies that source.read(start, end) returned exactly end-start bytes; if fewer bytes came back the CAB file is shorter than its structure demands and the archive is declared truncated. CAB files carry offset/size fields, so a short file fails this exact-length check. This is a strict validation: partial reads are never accepted.
Source
Thrown at packages/utils/src/ar/cab.ts:52
}
async function readExact(
source: ByteSource,
start: number,
end: number,
cabinetSize = source.size,
): Promise<Uint8Array> {
if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start || end > cabinetSize) {
throw new ArchiveError("Invalid CAB archive: metadata range is out of bounds");
}
let bytes: Uint8Array;
try {
bytes = await source.read(start, end);
} catch (error) {
if (error instanceof ArchiveError) throw error;
throw new ArchiveError(`Unable to read CAB archive: ${error instanceof Error ? error.message : String(error)}`);
}
if (bytes.byteLength !== end - start) throw new ArchiveError("Invalid CAB archive: truncated data");
return bytes;
}
function hasSignature(bytes: Uint8Array): boolean {
return bytes.byteLength >= 4 && bytes[0] === 0x4d && bytes[1] === 0x53 && bytes[2] === 0x43 && bytes[3] === 0x46;
}
function cabChecksum(bytes: Uint8Array, initial = 0): number {
let checksum = initial >>> 0;
let offset = 0;
while (offset + 4 <= bytes.byteLength) {
checksum ^= readUInt32LE(bytes, offset);
offset += 4;
}
const remaining = bytes.byteLength - offset;
let remainder = 0;
if (remaining === 3) {
remainder = (bytes[offset]! << 16) | (bytes[offset + 1]! << 8) | bytes[offset + 2]!;View on GitHub (pinned to 9690622007)
Solutions
- Re-download or re-copy the .cab file and compare its byte size (or checksum) against the original source.
- Verify the file starts with the MSCF signature (0x4D 0x53 0x43 0x46) — hasSignature() — to confirm it is actually a CAB.
- Check the file size on disk; if it is smaller than expected for this archive, the transfer was cut short.
- If using a custom ArchiveSource, ensure read() throws instead of returning short buffers when EOF is hit mid-range.
- Try extracting with an external tool (cabextract -t) to confirm the archive itself is intact before blaming your code.
Example fix
// before: trusting a possibly-incomplete download
const reader = await openCab(downloadedPath);
await reader.fileTable(); // Invalid CAB archive: truncated data
// after: verify size/signature first
const stat = await fs.stat(downloadedPath);
if (stat.size < expectedMinSize) throw new Error('CAB download incomplete, re-fetching');
const reader = await openCab(downloadedPath);
await reader.fileTable(); Defensive patterns
Strategy: validation
Validate before calling
const stat = await fs.stat(cabPath);
if (stat.size < 8) throw new Error(`File too small to be a CAB: ${stat.size} bytes`);
const head = new Uint8Array(await Bun.file(cabPath).slice(0, 4).arrayBuffer());
if (!(head[0] === 0x4d && head[1] === 0x53 && head[2] === 0x43 && head[3] === 0x46))
throw new Error('Missing MSCF signature — not a CAB file'); Type guard
function hasCabSignature(b: Uint8Array): boolean {
return b.byteLength >= 4 && b[0] === 0x4d && b[1] === 0x53 && b[2] === 0x43 && b[3] === 0x46;
} Try / catch
try {
return await readCabArchive(bytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('truncated data')) {
throw new Error(`CAB file is incomplete (${bytes.byteLength} bytes) — re-download it`);
}
throw err;
} Prevention
- Verify downloads against published sizes/checksums before parsing.
- Check the MSCF signature before opening.
- Avoid reading files while they are still being written or downloaded.
- Run cabextract -t on archives in CI fixtures to catch silent truncation.
When it happens
Trigger: Any header(), bytes(), fixed(), reserveHeader(), or fileTable() call where the underlying source returns a Uint8Array with byteLength < end - start — most often a file smaller than the header sizes/offsets declared inside it, or an offset pointing past EOF.
Common situations: Incomplete download of a .cab file; a truncated transfer (HTTP 200 body cut short); a corrupted/corrupted-by-antivirus archive; a file renamed to .cab that is not actually a CAB; passing the wrong start/end offsets to a custom source that silently clamps reads.
Related errors
- Invalid CAB archive: file has an invalid DOS timestamp
- Invalid CAB archive: truncated CFDATA header
- Invalid CAB archive: CFDATA expands to ${uncompressed} bytes
- Invalid CAB archive: truncated CFHEADER
- Unsupported CAB LZX window size: ${windowBits} bits (expecte
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/775ce2e3e3451ea3.
Report an issue: GitHub.