can1357/oh-my-pi · error · ArchiveError
Invalid ZIP archive: Unicode path extra field is too small
Error message
Invalid ZIP archive: Unicode path extra field is too small
What it means
Thrown by parseExtra when an extra field with id 0x7075 (Info-ZIP Unicode Path) is present but its data is shorter than the minimum 5 bytes (version byte + 4-byte CRC32 of the original name). A valid Unicode Path record must carry at least the version and checksum before any UTF-8 name payload.
Source
Thrown at packages/utils/src/ar/zip.ts:269
const value = new Date(year, month, day, hour, minute, second).getTime();
return Number.isFinite(value) ? value : undefined;
}
function parseExtra(extra: Uint8Array, rawName: Uint8Array): ParsedExtra {
const result: ParsedExtra = {};
let offset = 0;
while (offset < extra.byteLength) {
if (offset + 4 > extra.byteLength) throw new ArchiveError("Invalid ZIP archive: truncated extra-field header");
const id = readUInt16LE(extra, offset);
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);
}View on GitHub (pinned to 9690622007)
Solutions
- Test with `unzip -t`; standard tools may tolerate it, but rebuild anyway: `unzip` then `zip -r clean.zip .`.
- Recreate the archive with Info-ZIP, 7-Zip, or Python zipfile so Unicode paths are encoded per spec (or via the UTF-8 flag instead of 0x7075).
- Repair with `zip -FF` if the field region was corrupted.
- If you control the writer, emit version=1 + CRC32(name) + UTF-8 name, or set the general-purpose UTF-8 flag (0x0800) instead.
Example fix
// before: reading output of a custom writer emitting bare 0x7075 records
const zip = readZip(customUnicodeZip);
// after: rebuild so Unicode names use the UTF-8 flag
await $`unzip -q customUnicode.zip -d tmp`;
await $`zip -qr clean.zip .`.cwd("tmp"); // Info-ZIP sets UTF-8 flag / proper 0x7075
const zip = readZip("clean.zip"); Defensive patterns
Strategy: try-catch
Validate before calling
const probe = Bun.spawnSync(["unzip", "-t", path]);
if (probe.exitCode !== 0) throw new Error(`archive invalid; rebuild with a standard zip tool before reading: ${path}`); Try / catch
try {
const zip = readZip(path);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("Unicode path extra field is too small")) {
// producer's Unicode-path extras are nonstandard: re-zip to normalize
await $`unzip -q ${path} -d tmp`; await $`zip -qr clean.zip .`.cwd("tmp");
return readZip("clean.zip");
}
throw err;
} Prevention
- For Unicode filenames, prefer writers that set the UTF-8 flag (0x0800) instead of hand-rolled 0x7075 records.
- If emitting 0x7075 yourself, include version byte + CRC32(name) + UTF-8 payload — never a bare record.
- Test producer output with `zipinfo -v` to spot nonstandard extras before shipping.
- Rebuild legacy archives with a canonical tool during ingestion.
When it happens
Trigger: Calling zip info/read on an archive whose entries include a 0x7075 extra record with data length < 5 — produced by a writer that emits the record header/id without the required version+CRC prefix.
Common situations: Archives from nonstandard or homegrown zip writers attempting Unicode filename support; archives with extra fields rewritten by lossy tooling; fuzzed zips.
Related errors
- Invalid ZIP archive: malformed NTFS extra field
- Invalid ZIP archive: truncated extra-field header
- Invalid ZIP archive: malformed extra field
- Invalid ZIP archive: ${what} has an invalid range
- Invalid ZIP archive: ${what} exceeds archive size
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0530db3a92813359.
Report an issue: GitHub.