vercel-labs/skills · error · Error

Invalid zip archive: ${label} exceeds the safe integer range

Error message

Invalid zip archive: ${label} exceeds the safe integer range

What it means

The parser reads 64-bit zip fields with Buffer.readBigUInt64LE and converts them to JavaScript numbers. Zip64 fields can hold values up to 2^64-1, but a JS number only safely represents integers up to Number.MAX_SAFE_INTEGER (2^53-1). When a zip64 field (e.g. the zip64 end-of-central-directory offset, record size, or entry counts) exceeds that limit, this error is thrown rather than silently losing precision.

Source

Thrown at src/archive.ts:62

function findEndOfCentralDirectory(buffer: Buffer): number {
  const minOffset = Math.max(0, buffer.length - ZIP_MAX_COMMENT_SIZE - ZIP_END_MIN_SIZE);
  for (let offset = buffer.length - ZIP_END_MIN_SIZE; offset >= minOffset; offset--) {
    if (buffer.readUInt32LE(offset) !== ZIP_END_OF_CENTRAL_DIRECTORY) continue;

    const commentLength = buffer.readUInt16LE(offset + 20);
    if (offset + ZIP_END_MIN_SIZE + commentLength === buffer.length) {
      return offset;
    }
  }
  return -1;
}

function readUInt64AsNumber(buffer: Buffer, offset: number, label: string): number {
  ensureRange(buffer, offset, 8, label);
  const value = buffer.readBigUInt64LE(offset);
  if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
    throw new Error(`Invalid zip archive: ${label} exceeds the safe integer range`);
  }
  return Number(value);
}

function readCentralDirectory(
  buffer: Buffer,
  endOffset: number
): {
  entries: number;
  offset: number;
  size: number;
  trailerOffset: number;
} {
  const diskNumber = buffer.readUInt16LE(endOffset + 4);
  const centralDirectoryDisk = buffer.readUInt16LE(endOffset + 6);
  const entriesOnDisk = buffer.readUInt16LE(endOffset + 8);
  const totalEntries = buffer.readUInt16LE(endOffset + 10);
  const size = buffer.readUInt32LE(endOffset + 12);

View on GitHub (pinned to 435076e789)

Solutions

  1. Treat the input as corrupt: re-obtain the archive and verify it with `unzip -t` or `zip -T`.
  2. If you generate zips yourself, confirm your zip tool produces well-formed zip64 records (update Python zipfile / Info-ZIP / your zip library to the latest version).
  3. Validate buffer size first: if the buffer is smaller than the claimed 64-bit offset/size, the archive is truncated or garbage — reject it before parsing.
  4. Sanity-check that the buffer length itself is within a plausible range before calling the parser.

Example fix

// before
const zip = readZipArchive(buffer); // throws 'exceeds the safe integer range' on fuzzed input

// after
if (buffer.length > Number.MAX_SAFE_INTEGER) {
  throw new Error('Archive implausibly large');
}
try {
  const zip = readZipArchive(buffer);
} catch (e) {
  throw new Error(`Corrupt archive: ${(e as Error).message}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (buffer.length > Number.MAX_SAFE_INTEGER) {
  throw new Error('Implausible archive size');
}

Type guard

null

Try / catch

try {
  const zip = readZipArchive(buffer);
} catch (e) {
  if ((e as Error).message.includes('safe integer range')) {
    // corrupt zip64 field: quarantine the file
  }
  throw e;
}

Prevention

When it happens

Trigger: Parsing a zip64 archive whose end-of-central-directory offset, record size, or total-entries field is a 64-bit value larger than 2^53-1; corrupt or fuzzed zip64 records containing huge values; buffers whose random bytes are misinterpreted as a zip64 locator/record because the real structure is missing.

Common situations: Fuzz tests feeding random bytes that land on the zip64 parsing path; a corrupted archive where a 64-bit field overflows; extremely large synthetic archives (exabytes) that no real tool produces — in practice this signals corruption, not a legitimate file.

Related errors


AI-assisted analysis of vercel-labs/skills@435076e789 (2026-08-28). Data as JSON: /api/errors/7c3fa70e197cf3b9. Report an issue: GitHub.