can1357/oh-my-pi · error · ArchiveError

Invalid ZIP archive: malformed ZIP64 extra field

Error message

Invalid ZIP archive: malformed ZIP64 extra field

What it means

The ZIP64 extra field (id 0x0001) is present but too short to supply the first required value: the entry needs a 64-bit uncompressed size and the record contains fewer than 8 bytes at the required position. The library validates each field's length before reading and throws rather than returning garbage.

Source

Thrown at packages/utils/src/ar/zip.ts:308

	return result;
}

function applyZip64Values(
	extra: Uint8Array | undefined,
	current: Zip64Values,
	placeholders: Zip64Placeholders,
): Zip64Values {
	const needs =
		placeholders.uncompressedSize ||
		placeholders.compressedSize ||
		placeholders.localHeaderOffset ||
		placeholders.diskStart;
	if (!needs) return current;
	if (!extra) throw new ArchiveError("Invalid ZIP archive: missing ZIP64 extra field");
	let offset = 0;
	const result = { ...current };
	if (placeholders.uncompressedSize) {
		if (offset + 8 > extra.byteLength) throw new ArchiveError("Invalid ZIP archive: malformed ZIP64 extra field");
		result.uncompressedSize = readUInt64LE(extra, offset);
		offset += 8;
	}
	if (placeholders.compressedSize) {
		if (offset + 8 > extra.byteLength) throw new ArchiveError("Invalid ZIP archive: malformed ZIP64 extra field");
		result.compressedSize = readUInt64LE(extra, offset);
		offset += 8;
	}
	if (placeholders.localHeaderOffset) {
		if (offset + 8 > extra.byteLength) throw new ArchiveError("Invalid ZIP archive: malformed ZIP64 extra field");
		result.localHeaderOffset = readUInt64LE(extra, offset);
		offset += 8;
	}
	if (placeholders.diskStart) {
		if (offset + 4 > extra.byteLength) throw new ArchiveError("Invalid ZIP archive: malformed ZIP64 extra field");
		result.diskStart = readUInt32LE(extra, offset);
	}
	return result;

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the archive with unzip -t or 7z t; if corrupt, re-obtain it.
  2. Repack with a standard tool to regenerate correct ZIP64 metadata.
  3. If writing ZIP64 yourself, ensure the 0x0001 record is laid out in the fixed order uncompressed(8) + compressed(8) + offset(8) + disk(4), emitting exactly the fields matching the placeholders.

Example fix

// before: 4-byte zip64 payload for an 8-byte field
// after
// const buf = Buffer.alloc(8); buf.writeBigUInt64LE(BigInt(size)); extra = concat(extra, buf);
Defensive patterns

Strategy: try-catch

Validate before calling

const res = await $`7z t archive.zip`.quiet().nothrow();
if (res.exitCode !== 0) throw new Error("archive failed 7z integrity test");

Try / catch

try {
  await archive.readMember(path);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("malformed ZIP64 extra field")) {
    // mark archive as corrupt; fall back to repack with 7z then retry
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing a ZIP entry with an uncompressedSize placeholder (0xFFFFFFFF) whose 0x0001 extra record data is 1-7 bytes long — a malformed or truncated ZIP64 record.

Common situations: Archives produced by non-conformant ZIP64 writers, records truncated by corruption, tools that strip or rewrite extra fields incorrectly, malicious/fuzzed inputs.

Understand the failure class

Related errors


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