can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: reserved CFHEADER fields must be zero
Error message
Invalid CAB archive: reserved CFHEADER fields must be zero
What it means
The CFHEADER contains three reserved 32-bit fields (offsets 4, 12, and 20) that the CAB specification requires to be zero. The library rejects any cabinet where any of these is non-zero, since a valid writer never sets them and non-zero values indicate a corrupt or hand-crafted file.
Source
Thrown at packages/utils/src/ar/cab.ts:248
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);
const flags = readUInt16LE(fixed, 30);
if (flags & 0x0003) throw new ArchiveError("Unsupported multi-volume CAB archive (previous/next cabinet link)");
assertEntryCount(folderCount + fileCount, options.limits);
if (folderCount === 0 && fileCount !== 0)View on GitHub (pinned to 9690622007)
Solutions
- Re-obtain the archive from a trusted source; the header is corrupt and cannot be safely repaired by the caller.
- Inspect header bytes 4-7, 12-15, and 20-23 with a hex dump to confirm which reserved field is non-zero.
- If the file comes from an in-house generator, fix the writer to zero the reserved fields per the MS-CAB specification.
- Test the cabinet with a reference tool (e.g. cabextract) to see whether it is generally considered corrupt.
Defensive patterns
Strategy: validation
Validate before calling
import { readUInt32LE } from "@oh-my-pi/pi-utils/ar/bytes";
const fixed = new Uint8Array(buf.slice(0, 36));
if (fixed[4] !== 0 || fixed[5] !== 0 || fixed[6] !== 0 || fixed[7] !== 0 ||
fixed[12] !== 0 || fixed[13] !== 0 || fixed[14] !== 0 || fixed[15] !== 0 ||
fixed[20] !== 0 || fixed[21] !== 0 || fixed[22] !== 0 || fixed[23] !== 0) {
throw new Error("CAB reserved header fields are non-zero; file is corrupt");
} Try / catch
try {
const entries = await readCab(source);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("reserved CFHEADER fields")) {
logger.warn("CAB header corrupt; skipping archive", { path });
return null;
}
throw err;
} Prevention
- Treat this as file corruption: re-download instead of trying to repair.
- Validate checksums on transfer for archive files.
- If generating CABs, zero all reserved header fields per the spec.
When it happens
Trigger: Calling readCab() on a file with a valid 'MSCF' signature but non-zero data at header offsets 4, 12, or 20 — typically a bit-flipped, partially overwritten, or maliciously malformed cabinet.
Common situations: Corrupted downloads or disk-level damage that only flipped a few header bytes, fuzzed or hand-edited test files, and cabinets assembled by broken third-party tooling that writes garbage into reserved fields.
Related errors
- Invalid CAB archive: files exist without a folder
- Invalid CAB archive: expected ${CAB_SIGNATURE} signature
- Invalid CAB archive: CFFILE table offset is out of bounds
- Unsupported CAB format version ${fixed[25]}.${fixed[24]} (ex
- Invalid CAB archive: CFFOLDER table is out of bounds
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/39d68b1a66273b25.
Report an issue: GitHub.