can1357/oh-my-pi · error · ArchiveError
Invalid ZIP archive: ${what} exceeds archive size
Error message
Invalid ZIP archive: ${what} exceeds archive size What it means
checkedEnd in zip.ts throws this when start + size computes past the end of the archive (or overflows a safe integer). It protects callers from records that claim data beyond the file, which would otherwise produce out-of-bounds reads or undefined behavior downstream.
Source
Thrown at packages/utils/src/ar/zip.ts:107
}
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,
tail: Uint8Array,
tailStart: number,
eocdOffset: number,
): Promise<CentralDirectoryInfo | undefined> {View on GitHub (pinned to 9690622007)
Solutions
- Run `unzip -t` / re-download the archive; this error almost always means real truncation
- If the ZIP came from your own writer, ensure the central directory is written after all entry data
- For large archives, confirm the file wasn't cut by a size limit (upload cap, tar slice, git-lfs filter)
Example fix
// before
const zip = await readZip(await Bun.file(upload.path).bytes());
// after
const file = Bun.file(upload.path);
if (file.size < upload.expectedBytes) throw new Error(`zip truncated: ${file.size} < ${upload.expectedBytes}`);
const zip = await readZip(await file.bytes()); Defensive patterns
Strategy: validation
Validate before calling
const file = Bun.file(zipPath);
if (file.size < minimumExpectedBytes) {
throw new Error(`zip truncated: ${file.size} bytes, expected >= ${minimumExpectedBytes}`);
}
const bytes = await file.bytes();
const dv = new DataView(bytes.buffer);
if (dv.getUint32(bytes.length - 22, true) !== 0x06054b50 && !findEocdSig(bytes)) {
throw new Error("zip EOCD not at expected location — likely truncated");
} Try / catch
try {
const zip = await readZip(bytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("exceeds archive size")) {
return { ok: false, reason: "truncated zip" };
}
throw err;
} Prevention
- Verify total file size against a manifest/checksum after download
- Watch for size caps (upload limits, git filters, tar slices) that silently truncate
- Test archives with `unzip -t` before feeding them to automated pipelines
When it happens
Trigger: readZip parsing a central directory entry, local header, or data span whose declared offset+size exceeds source size; typical for truncated files or forged header values.
Common situations: Partially downloaded ZIPs; archives on a disk that filled up mid-write; entries listed in the central directory whose local data was never written.
Related errors
- Invalid CAB archive: metadata range is out of bounds
- Invalid CAB archive: truncated data
- Invalid CAB archive: truncated CFDATA header
- Invalid CAB archive: truncated CFHEADER
- Invalid RPM package: tag ${tag} points outside header data
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a210b8266c63beda.
Report an issue: GitHub.