can1357/oh-my-pi · error · ArchiveError

ASAR archive is too large to encode safely

Error message

ASAR archive is too large to encode safely

What it means

After computing dataOffset (Pickle prefix + header) plus the accumulated payload size, encodeAsar checks that the total archive size is a safe integer (< 2^53). If dataOffset + payloadSize exceeds Number.MAX_SAFE_INTEGER the offsets written into the JSON header could not be addressed reliably, so it throws instead of producing a corrupt archive.

Source

Thrown at packages/utils/src/ar/asar.ts:457

			if (!Number.isSafeInteger(member[1].byteLength) || !Number.isSafeInteger(payloadSize + member[1].byteLength)) {
				throw new ArchiveError("ASAR payload is too large to encode safely");
			}
			directory.files[name] = { size: member[1].byteLength, offset: String(payloadSize) };
			payloads.push(member[1]);
			payloadSize += member[1].byteLength;
		}

		const jsonBytes = ASAR_HEADER_ENCODER.encode(JSON.stringify(root));
		const paddedJsonSize = alignAsarPayload(jsonBytes.byteLength);
		const innerPayloadSize = 4 + paddedJsonSize;
		const headerSize = 4 + innerPayloadSize;
		if (jsonBytes.byteLength > 0xffffffff || headerSize > 0xffffffff) {
			throw new ArchiveError("ASAR header is too large to encode");
		}
		const dataOffset = ASAR_PICKLE_PREFIX_SIZE + headerSize;
		const archiveSize = dataOffset + payloadSize;
		if (!Number.isSafeInteger(archiveSize)) {
			throw new ArchiveError("ASAR archive is too large to encode safely");
		}
		let output: Uint8Array;
		try {
			output = new Uint8Array(archiveSize);
		} catch {
			throw new ArchiveError("ASAR archive is too large to encode in memory");
		}
		writeUInt32LE(output, 0, 4);
		writeUInt32LE(output, 4, headerSize);
		writeUInt32LE(output, 8, innerPayloadSize);
		writeUInt32LE(output, 12, jsonBytes.byteLength);
		output.set(jsonBytes, ASAR_JSON_OFFSET);
		let offset = dataOffset;
		for (const payload of payloads) {
			output.set(payload, offset);
			offset += payload.byteLength;
		}
		return output;

View on GitHub (pinned to 9690622007)

Solutions

  1. Split the content into multiple archives, each with a payload well under the safe-integer bound.
  2. Validate that members are genuine Uint8Arrays with plausible byteLength before encoding.
  3. Stream to disk incrementally instead of one monolithic encodeAsar call for very large datasets.
  4. Catch ArchiveError and report the attempted archiveSize for diagnostics.

Example fix

// before
await encodeAsar(unboundedHugeIterable); // archiveSize > 2^53
// after
await Promise.all(partition(unboundedHugeIterable, MAX_BYTES).map(encodeAsar));
Defensive patterns

Strategy: validation

Validate before calling

function assertSafeArchiveSize(members, headerReserve = 1 << 20) {
  let payloadSize = 0;
  for (const [, data] of members) {
    payloadSize += data.byteLength;
    if (!Number.isSafeInteger(payloadSize + headerReserve)) {
      throw new Error('Archive would exceed safe integer size; split it');
    }
  }
}
assertSafeArchiveSize(members);

Try / catch

try {
  const archive = await encodeAsar(members);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('archive is too large to encode safely')) {
    throw new Error('Total archive size exceeds Number.MAX_SAFE_INTEGER; split content into multiple archives');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling encodeAsar/encodeArchive/bytes where the combined byteLength of all member payloads plus the header offset exceeds Number.MAX_SAFE_INTEGER (2^53-1, ~9 PiB). Practically only reachable with synthetic/unsized Uint8Array-like inputs.

Common situations: Encoding an unbounded iterable of huge members in tests or data pipelines; a member object with an inflated byteLength; attempts to build a single multi-petabyte archive instead of splitting it.

Related errors


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