can1357/oh-my-pi · error · ArchiveError

Invalid CAB archive: MSZIP decompression failed${error insta

Error message

Invalid CAB archive: MSZIP decompression failed${error instanceof Error ? `: ${error.message}` : ""}

What it means

Thrown by CabFolder.#decode when node:zlib's inflateRawSync rejects the deflate stream inside an MSZIP block (after the 'CK' signature). The original zlib error message is appended so you can see the underlying zlib failure (e.g. 'invalid distance too far back', unexpected end of file). MSZIP inflate also receives the previous 32KB of folder output as the dictionary window, so mid-folder failures can indicate missing or wrong preceding data.

Source

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

			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);
			}
			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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the appended zlib message to identify the inflate failure mode
  2. Re-download/verify the archive with `cabextract -t`; re-obtain if corrupt
  3. If failure happens deep in a multi-block folder, suspect corruption in an earlier block (it seeds the MSZIP dictionary)
  4. Regenerate the cabinet with makecab/7-Zip if you control production; otherwise report a bug if cabextract succeeds

Example fix

// before
try { await extractCab(path, dest); } catch { console.log('failed'); }
// after
try { await extractCab(path, dest); }
catch (err) {
  if (err instanceof ArchiveError && err.message.includes('MSZIP decompression failed'))
    console.error(`archive corrupt at MSZIP block: ${err.message}`);
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

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

Try / catch

try {
  await readCab(source, opts);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('MSZIP decompression failed')) {
    logger.error('MSZIP inflate failed', { path: archivePath, detail: err.message });
    throw new Error(`Archive corrupt at an MSZIP block: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: readCab() indexed a method-1 folder and zlib.inflateRawSync(payload.subarray(2), {dictionary, maxOutputLength}) threw — corrupt deflate stream, wrong dictionary window due to an earlier failed block, or truncated payload.

Common situations: Partially corrupted archives; extracting method-1 cabinets where an earlier block was silently damaged so the 32KB MSZIP history window is wrong; files from unreliable sources.

Related errors


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