can1357/oh-my-pi · error · ArchiveError
Invalid ZIP archive: ${what} has an invalid range
Error message
Invalid ZIP archive: ${what} has an invalid range What it means
checkedEnd in zip.ts validates that a start/size pair describes a sane in-range span before any ZIP structure (local header, data, central directory entry) is used. This branch fires when either value is negative, non-finite, or not a safe integer — i.e. the ZIP metadata is nonsensical, not merely too large.
Source
Thrown at packages/utils/src/ar/zip.ts:103
interface ParsedExtra {
zip64?: Uint8Array;
unicodePath?: string;
mtimeMs?: number;
}
interface ParsedZipEntry {
entry: ArchiveIndexEntry;
isSymlink: boolean;
}
function archiveError(error: unknown, context: string): ArchiveError {
if (error instanceof ArchiveError) return error;
return new ArchiveError(`${context}: ${error instanceof Error ? error.message : String(error)}`);
}
function checkedEnd(start: number, size: number, archiveSize: number, what: string): number {
if (!Number.isSafeInteger(start) || !Number.isSafeInteger(size) || start < 0 || size < 0) {
throw new ArchiveError(`Invalid ZIP archive: ${what} has an invalid range`);
}
const end = start + size;
if (!Number.isSafeInteger(end) || end > archiveSize) {
throw new ArchiveError(`Invalid ZIP archive: ${what} exceeds archive size`);
}
return end;
}
function findEocd(tail: Uint8Array): number {
for (let offset = tail.byteLength - EOCD_LENGTH; offset >= 0; offset--) {
if (readUInt32LE(tail, offset) !== EOCD_SIGNATURE) continue;
if (offset + EOCD_LENGTH + readUInt16LE(tail, offset + 20) === tail.byteLength) return offset;
}
throw new ArchiveError("Invalid ZIP archive: missing end of central directory");
}
async function readZip64Info(
source: ByteSource,View on GitHub (pinned to 9690622007)
Solutions
- Test the archive with `unzip -t` to confirm corruption, then re-obtain it
- If parsing untrusted input, treat this as an expected failure and reject the file up front
- Check any code that pre-processes or patches ZIP fields for integer overflow or wrong endianness
Example fix
// before
await readZip(untrustedBytes);
// after
if (!looksLikeZip(untrustedBytes)) throw new Error("not a zip");
try {
await readZip(untrustedBytes);
} catch (e) {
if (e instanceof ArchiveError) return rejectUpload("corrupt zip: " + e.message);
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!Number.isSafeInteger(bytes.length) || bytes.length < 22) throw new Error("not a plausible zip");
// check EOCD signature exists in tail
const dec = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
let eocd = -1;
for (let i = bytes.length - 22; i >= Math.max(0, bytes.length - 22 - 65535); i--) {
if (dec.getUint32(i, true) === 0x06054b50) { eocd = i; break; }
}
if (eocd < 0) throw new Error("zip EOCD missing — refusing to parse"); Try / catch
try {
const zip = await readZip(bytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("invalid range")) {
return quarantine(err, "zip metadata nonsensical — likely corrupt or hostile input");
}
throw err;
} Prevention
- Validate ZIP origin: check checksums/size before parsing untrusted files
- Never accept archives from untrusted sources without size/structure validation
- Keep the reader's errors (ArchiveError) mapped to a user-facing 'corrupt file' path
When it happens
Trigger: readZip or its helpers computing a header/data/central-directory span where a parsed 32/64-bit field decodes to a negative or unsafe-integer value (e.g. a corrupted size or offset field, or a bad ZIP64 extra field).
Common situations: Corrupted ZIPs from interrupted downloads; ZIP files with flipped bits in central-directory fields; hand-modified archives; fuzzed or malicious inputs.
Related errors
- Invalid ZIP archive: missing end of central directory
- Invalid ARJ ${field}: missing terminator
- Invalid ARJ local header
- Invalid ARJ archive: no members
- ASAR member '${formatArchivePathForError(memberPath)}' has a
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/52ea30aff9e39419.
Report an issue: GitHub.