can1357/oh-my-pi · error · ArchiveError

Archive uses offsets or sizes too large to read safely

Error message

Archive uses offsets or sizes too large to read safely

What it means

readUInt64LE decodes a little-endian 64-bit integer as a JS number. JavaScript numbers can only exactly represent integers up to Number.MAX_SAFE_INTEGER (2^53-1), so any u64 whose value exceeds that is rejected with this ArchiveError rather than silently returning a corrupted value that could cause wrong offsets and out-of-bounds reads.

Source

Thrown at packages/utils/src/ar/bytes.ts:18

import { ArchiveError } from "./error";

/** Shared UTF-8 decoder for archive member names and text payloads. */
export const UTF8_DECODER = new TextDecoder();

export function readUInt16LE(bytes: Uint8Array, offset: number): number {
	return bytes[offset]! | (bytes[offset + 1]! << 8);
}

export function readUInt32LE(bytes: Uint8Array, offset: number): number {
	return (bytes[offset]! | (bytes[offset + 1]! << 8) | (bytes[offset + 2]! << 16) | (bytes[offset + 3]! << 24)) >>> 0;
}

/** Read a u64 as a JS number, rejecting values beyond `Number.MAX_SAFE_INTEGER`. */
export function readUInt64LE(bytes: Uint8Array, offset: number): number {
	const value = readUInt32LE(bytes, offset) + readUInt32LE(bytes, offset + 4) * 0x100000000;
	if (!Number.isSafeInteger(value)) {
		throw new ArchiveError("Archive uses offsets or sizes too large to read safely");
	}
	return value;
}

export function readUInt16BE(bytes: Uint8Array, offset: number): number {
	return (bytes[offset]! << 8) | bytes[offset + 1]!;
}

export function readUInt32BE(bytes: Uint8Array, offset: number): number {
	return ((bytes[offset]! << 24) | (bytes[offset + 1]! << 16) | (bytes[offset + 2]! << 8) | bytes[offset + 3]!) >>> 0;
}

/** Read a big-endian u64 as a JS number, rejecting unsafe values. */
export function readUInt64BE(bytes: Uint8Array, offset: number): number {
	const value = readUInt32BE(bytes, offset) * 0x100000000 + readUInt32BE(bytes, offset + 4);
	if (!Number.isSafeInteger(value)) {
		throw new ArchiveError("Archive uses offsets or sizes too large to read safely");
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the archive is well-formed: re-check parse alignment (record signatures, header sizes) before this read — a huge value often means misalignment.
  2. Treat the input as untrusted/corrupt: reject the archive rather than attempting repair.
  3. If you legitimately need >2^53 values, decode with BigInt locally instead of this helper (the library intentionally does not).
  4. Confirm the file is not truncated or bit-rotted; re-download or re-extract the source archive.

Example fix

// before
const offset = readUInt64LE(bytes, extraFieldOffset); // throws on 0xFFFFFFFFFFFFFFFF
// after
if (bytes.slice(extraFieldOffset, extraFieldOffset + 8).every(b => b === 0xff)) {
  throw new Error("archive declares invalid ZIP64 sentinel size");
}
const offset = readUInt64LE(bytes, extraFieldOffset);
Defensive patterns

Strategy: validation

Validate before calling

function safeU64LE(bytes, offset) {
  const lo = bytes[offset] | bytes[offset+1]<<8 | bytes[offset+2]<<16 | bytes[offset+3]<<24;
  const hi = bytes[offset+4] | bytes[offset+5]<<8 | bytes[offset+6]<<16 | bytes[offset+7]<<24;
  if (hi > 0x1fffff) throw new Error("u64 field exceeds safe integer range at offset " + offset);
  return lo + hi * 0x100000000;
}

Type guard

function isSafeArchiveValue(v) {
  return typeof v === "number" && Number.isSafeInteger(v) && v >= 0;
}

Try / catch

let offset;
try {
  offset = readUInt64LE(bytes, pos);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("too large to read safely")) {
    throw new Error(`corrupt or malicious archive: unsafe 64-bit field at byte ${pos}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Reading a ZIP (incl. ZIP64), ASAR, or CAB field via readUInt64LE where the encoded value exceeds 2^53-1 — e.g. a ZIP64 extra field declaring an astronomically large offset/size, or a corrupted/truncated byte stream misaligned so adjacent bytes form a huge value.

Common situations: Maliciously crafted or corrupted archives (poisoned ZIP64 fields); reading at a wrong offset due to earlier parsing drift; archives produced by tools writing placeholder 0xFFFFFFFFFFFFFFFF values that the reader does not expect.

Related errors


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