can1357/oh-my-pi · error · ArchiveError

Invalid CAB archive: CFDATA block ${block} produced ${decode

Error message

Invalid CAB archive: CFDATA block ${block} produced ${decoded.byteLength} bytes, expected ${uncompressed}

What it means

Thrown by CabFolder.#decode after decompressing a block: the decoder produced a different number of bytes than the block header's cbUncomp promised. Caught for MSZIP (inflate output length) and LZX (decompressFrame) results; stored blocks are size-checked earlier. Guards against decoders silently emitting truncated or oversized data.

Source

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

				}
				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);
			}
			if (decoded.byteLength !== uncompressed) {
				throw new ArchiveError(
					`Invalid CAB archive: CFDATA block ${block} produced ${decoded.byteLength} bytes, expected ${uncompressed}`,
				);
			}
			output.set(decoded, outputPosition);
			outputPosition += decoded.byteLength;
			position = payloadEnd;
		}
		return output;
	}
}

class CabMemberSource implements MemberSource {
	readonly #folder: CabFolder;
	readonly #offset: number;
	readonly #declaredSize: number;

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the archive with `cabextract -t file.cab` to confirm the file is corrupt
  2. Re-download the archive from its source and compare hashes
  3. If you generate cabinets, ensure cbUncomp exactly equals the uncompressed block size
  4. If independent tools accept the file, report a reader bug (include the file and block index from the message)
Defensive patterns

Strategy: try-catch

Validate before calling

const expected = await getExpectedSha256(path);
if ((await sha256(path)) !== expected) throw new Error('archive hash mismatch before extraction');

Try / catch

try {
  await readCab(source, opts);
} catch (err) {
  if (err instanceof ArchiveError && /block \d+ produced \d+ bytes/.test(err.message))
    throw new Error(`Decompressed block size mismatch — archive corrupt or mis-declared: ${err.message}`);
  throw err;
}

Prevention

When it happens

Trigger: readCab() indexed a folder where zlib.inflateRawSync returned fewer/more bytes than uncompressed (bounded by maxOutputLength), or LzxDecoder.decompressFrame returned a frame of unexpected size — corrupt stream or header mismatch.

Common situations: Truncated or bit-flipped compressed data; cabinets written by tools that mis-declare cbUncomp; LZX streams with damaged frame headers.

Related errors


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