can1357/oh-my-pi · error · ArchiveError

Invalid CAB archive: uncompressed CFDATA sizes do not match

Error message

Invalid CAB archive: uncompressed CFDATA sizes do not match

What it means

Thrown by CabFolder.#decode when the folder's compression method is 0 (none/stored) but a block's cbData (compressed) and cbUncomp (uncompressed) sizes differ. For stored blocks the payload is used verbatim, so the two sizes must be identical; a discrepancy means the block header is inconsistent.

Source

Thrown at packages/utils/src/ar/cab.ts:186

		}
		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;
			const payloadEnd = payloadStart + compressed;
			const payload = bytes.subarray(payloadStart, payloadEnd);
			let decoded: Uint8Array;
			if (description.method === 0) {
				if (compressed !== uncompressed) {
					throw new ArchiveError("Invalid CAB archive: uncompressed CFDATA sizes do not match");
				}
				decoded = payload;
			} else if (description.method === 1) {
				if (payload.byteLength < 2 || payload[0] !== 0x43 || payload[1] !== 0x4b) {
					throw new ArchiveError("Invalid CAB archive: MSZIP block is missing its CK signature");
				}
				try {
					const dictionary = output.subarray(Math.max(0, outputPosition - MAX_DATA_OUTPUT), outputPosition);
					decoded = new Uint8Array(
						zlib.inflateRawSync(payload.subarray(2), { dictionary, maxOutputLength: uncompressed }),
					);
				} catch (error) {
					throw new ArchiveError(
						`Invalid CAB archive: MSZIP decompression failed${error instanceof Error ? `: ${error.message}` : ""}`,
					);
				}
			} else {
				decoded = lzx!.decompressFrame(payload, uncompressed);

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-verify the archive with an independent tool (cabextract/7-Zip) to confirm the file is malformed
  2. Regenerate the cabinet with makecab or 7-Zip if you control creation
  3. If you wrote the CAB generator, ensure method-0 blocks always set cbData = cbUncomp
  4. If the file is trusted and a standard tool accepts it, report a reader bug with the file

Example fix

// before (custom CAB writer)
block.cbData = payload.length;
block.cbUncomp = raw.length;
// after
if (method === 0) { block.cbData = raw.length; block.cbUncomp = raw.length; }
Defensive patterns

Strategy: try-catch

Validate before calling

const t = Bun.$`cabextract -t ${path}`.quiet().nothrow();
if ((await t).exitCode !== 0) throw new Error(`malformed cabinet: ${path}`);

Try / catch

try {
  await readCab(source, opts);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('uncompressed CFDATA sizes do not match'))
    throw new Error('Cabinet has an invalid stored (method 0) block — regenerate it with a standard tool.');
  throw err;
}

Prevention

When it happens

Trigger: readCab() indexed a cabinet whose CFFOLDER typeA&0x000f equals 0, but a CFDATA block has cbData !== cbUncomp — a malformed header from a buggy writer or bit corruption in the 2 size fields.

Common situations: Cabinets produced by non-standard or buggy archivers; corrupted files where the size fields were damaged; crafted inputs during security testing.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/870f67cef3593583. Report an issue: GitHub.