can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: truncated CFHEADER
Error message
Invalid CAB archive: truncated CFHEADER
What it means
Thrown by readCabArchive when the ByteSource is smaller than the 36-byte fixed CFHEADER, so no CAB header could possibly be present. This is the first structural check in CAB indexing — it fires on empty files, tiny files, or streams that ended before the header arrived.
Source
Thrown at packages/utils/src/ar/cab.ts:244
this.#offset = offset;
this.#declaredSize = size;
}
async read(size: number, memberPath: string): Promise<Uint8Array> {
if (size !== this.#declaredSize) {
throw new ArchiveError(`Invalid CAB archive: size changed while extracting '${memberPath}'`);
}
const folder = await this.#folder.readAll();
const end = this.#offset + size;
if (!Number.isSafeInteger(end) || this.#offset < 0 || end > folder.byteLength) {
throw new ArchiveError(`Invalid CAB archive: member '${memberPath}' is outside its folder data`);
}
return folder.slice(this.#offset, end);
}
}
async function readCabArchive(source: ByteSource, options: Parameters<FormatReader>[1]): Promise<ArchiveIndexEntry[]> {
if (source.size < FIXED_HEADER_SIZE) throw new ArchiveError("Invalid CAB archive: truncated CFHEADER");
const fixed = await readExact(source, 0, FIXED_HEADER_SIZE);
if (!hasSignature(fixed)) throw new ArchiveError(`Invalid CAB archive: expected ${CAB_SIGNATURE} signature`);
if (readUInt32LE(fixed, 4) !== 0 || readUInt32LE(fixed, 12) !== 0 || readUInt32LE(fixed, 20) !== 0) {
throw new ArchiveError("Invalid CAB archive: reserved CFHEADER fields must be zero");
}
const cabinetSize = readUInt32LE(fixed, 8);
if (cabinetSize < FIXED_HEADER_SIZE || cabinetSize > source.size) {
throw new ArchiveError("Invalid CAB archive: declared cabinet size is out of bounds");
}
const fileTableOffset = readUInt32LE(fixed, 16);
if (fileTableOffset < FIXED_HEADER_SIZE || fileTableOffset > cabinetSize) {
throw new ArchiveError("Invalid CAB archive: CFFILE table offset is out of bounds");
}
if (fixed[24] !== 3 || fixed[25] !== 1) {
throw new ArchiveError(`Unsupported CAB format version ${fixed[25]}.${fixed[24]} (expected 1.3)`);
}
const folderCount = readUInt16LE(fixed, 26);
const fileCount = readUInt16LE(fixed, 28);View on GitHub (pinned to 9690622007)
Solutions
- Check the file size on disk (ls -l / stat) — if it is tiny or 0, re-download or re-copy the archive
- Confirm you are pointing the reader at the .cab file, not an index/manifest or temp file
- Verify the upstream transfer completed (Content-Length match, checksum comparison)
- If reading from a stream, ensure the source reports the true size and was fully consumed/flushed before indexing
Example fix
// before
const archive = Bun.file(maybePath);
await readCab(new ByteSource(archive), opts);
// after
const archive = Bun.file(maybePath);
if (archive.size < 36) throw new Error(`${maybePath} is too small to be a CAB archive (${archive.size} bytes)`);
await readCab(new ByteSource(archive), opts); Defensive patterns
Strategy: validation
Validate before calling
const file = Bun.file(path);
const stat = await file.stat();
if (stat.size < 36) throw new Error(`${path} is ${stat.size} bytes — too small to be a CAB archive`); Try / catch
try {
await readCab(source, opts);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('truncated CFHEADER'))
throw new Error(`File is not a complete CAB archive (${source.size} bytes): ${path}`);
throw err;
} Prevention
- Check file size before pointing the reader at a path
- Confirm downloads completed (Content-Length / hash) before extraction
- Exclude zero-byte or placeholder files from archive processing pipelines
When it happens
Trigger: Calling readCab on a source with size < 36: empty file, a few-byte stub, a truncated download, or passing the wrong file/path to the reader.
Common situations: Zero-byte files created by failed downloads; accidentally pointing the extractor at a lock/partial file; reading from a truncated network response.
Related errors
- Invalid CAB archive: truncated data
- Invalid CAB archive: truncated CFDATA header
- Invalid ARJ archive: missing main header
- Invalid ARJ main header
- ASAR header is too large to encode
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/83262ae60ae76aa8.
Report an issue: GitHub.