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
- Verify the archive is well-formed: re-check parse alignment (record signatures, header sizes) before this read — a huge value often means misalignment.
- Treat the input as untrusted/corrupt: reject the archive rather than attempting repair.
- If you legitimately need >2^53 values, decode with BigInt locally instead of this helper (the library intentionally does not).
- 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
- Sanity-check every offset/size against the actual file size before use.
- Validate record signatures/magic before trusting subsequent field reads.
- Reject 0xFFFFFFFF/0xFFFFFFFFFFFFFFFF sentinel patterns when your format version does not expect them.
- Bound total parsed structures (entries, extra fields) to protect against crafted archives.
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
- Invalid ARJ archive: truncated ${what}
- Invalid ARJ ${field}: missing terminator
- Invalid ARJ basic header size
- Invalid ARJ basic header CRC32
- Invalid ARJ archive: too many extended headers
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/268c86d0cd55072a.
Report an issue: GitHub.