can1357/oh-my-pi · error · ArchiveError

Invalid ZIP archive: extended timestamp extra field is too s

Error message

Invalid ZIP archive: extended timestamp extra field is too small

What it means

The ZIP central-directory/local-header extra field contains an extended timestamp record (header id 0x5455) whose data is too short to even hold the 1-byte flags field. The library throws instead of reading out of bounds, because a truncated optional extra field indicates a corrupt or hand-malformed archive.

Source

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

		const size = readUInt16LE(extra, offset + 2);
		const dataStart = offset + 4;
		const dataEnd = dataStart + size;
		if (dataEnd > extra.byteLength) throw new ArchiveError("Invalid ZIP archive: malformed extra field");
		const data = extra.subarray(dataStart, dataEnd);
		if (id === 0x0001) {
			result.zip64 = data;
		} else if (id === 0x7075) {
			if (data.byteLength < 5) throw new ArchiveError("Invalid ZIP archive: Unicode path extra field is too small");
			if (data[0] === 1 && readUInt32LE(data, 1) === crc32(rawName)) {
				try {
					result.unicodePath = UTF8_FATAL_DECODER.decode(data.subarray(5));
				} catch {
					// A bad optional Unicode path falls back to the header name.
				}
			}
		} else if (id === 0x5455) {
			if (data.byteLength < 1)
				throw new ArchiveError("Invalid ZIP archive: extended timestamp extra field is too small");
			if ((data[0]! & 1) !== 0) {
				if (data.byteLength < 5)
					throw new ArchiveError("Invalid ZIP archive: extended timestamp extra field is too small");
				result.mtimeMs = (readUInt32LE(data, 1) | 0) * 1000;
			}
		} else if (id === 0x000a && result.mtimeMs === undefined) {
			result.mtimeMs = parseNtfsMtime(data);
		}
		offset = dataEnd;
	}
	return result;
}

function applyZip64Values(
	extra: Uint8Array | undefined,
	current: Zip64Values,
	placeholders: Zip64Placeholders,
): Zip64Values {

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-obtain the archive from its original source and verify its checksum/hash.
  2. Test the archive with unzip -t (or 7z t) to confirm it is corrupt.
  3. If the archive is produced by your own pipeline, fix the code writing the 0x5455 record to always emit the 1 flag byte (and 4 mtime bytes when flag bit 0 is set).
  4. If you only need the data and the archive is trusted, strip or repair the extra field with a tool like zip -FF.

Example fix

// malformed: 0x5455 record with empty data
// fix: regenerate the archive with a correct writer, e.g. Info-ZIP/Python zipfile, which always writes
// flags byte + optional 4-byte mtime:
// python -c "import zipfile; zipfile.ZipFile('fixed.zip','w').write('file.txt')"
Defensive patterns

Strategy: validation

Validate before calling

// before trusting a zip source, sanity-check its integrity externally
import { $ } from "bun";
const res = await $`unzip -t archive.zip`.quiet().nothrow();
if (res.exitCode !== 0) throw new Error("archive corrupt: " + await res.stderr.text());

Try / catch

try {
  await archive.readMember(path);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("extended timestamp extra field is too small")) {
    // treat as corrupt input: surface to user / re-fetch source
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing a ZIP whose extra field declares id 0x5455 with a declared data size of 0 bytes (data.byteLength < 1), typically from a truncated download, a corrupt archive, or a tool that wrote a zero-length extended-timestamp record.

Common situations: Corrupted downloads, archives edited or patched by scripts that rewrite extra fields, maliciously crafted ZIPs (zip-bomb/fuzzer inputs), or files produced by non-conformant archivers.

Related errors


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