can1357/oh-my-pi · error · ArchiveError

ASAR header is too large to encode

Error message

ASAR header is too large to encode

What it means

The ASAR header is the Pickle-framed JSON directory tree, and its size fields are 32-bit. encodeAsar throws when the serialized JSON of the file tree exceeds 0xffffffff bytes or the aligned/framed header size overflows a uint32 — i.e. the tree has so many entries (or such long paths) that the header can't be represented in the ASAR format.

Source

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

			}
			const name = parts.at(-1)!;
			if (directory.files[name]) {
				throw new ArchiveError(`Duplicate or conflicting ASAR member path '${memberPath}'`);
			}
			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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Reduce the number of members: exclude vendored/generated directories (node_modules, build outputs) before encoding.
  2. Shorten member paths by restructuring the archive root or storing common prefixes out-of-band.
  3. Split content across multiple ASAR archives.
  4. Catch ArchiveError and report member count/total path length to guide the caller.

Example fix

// before
await encodeAsar([...everyFileInProject]); // header JSON > 4 GiB
// after
const filtered = members.filter(([p]) => !p.startsWith('node_modules/'));
await encodeAsar(filtered);
Defensive patterns

Strategy: validation

Validate before calling

function estimateHeaderBytes(members) {
  // rough upper bound: ~60 bytes of JSON overhead per entry plus path length
  let est = 0;
  for (const [p] of members) est += p.length + 120;
  return est;
}
if (estimateHeaderBytes(members) > 0xf0000000) {
  throw new Error('Too many members: ASAR header JSON would exceed 32-bit size fields');
}

Try / catch

try {
  const archive = await encodeAsar(members);
} catch (err) {
  if (err instanceof ArchiveError && err.message === 'ASAR header is too large to encode') {
    throw new Error('Reduce member count or split into multiple ASAR archives');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling encodeAsar/encodeArchive/bytes with millions of members or extremely long path names so JSON.stringify(root) exceeds 4 GiB, or the padded/framed header size exceeds 0xffffffff.

Common situations: Archiving node_modules or a huge source tree with hundreds of thousands of files (header JSON can grow to hundreds of MB, though 4 GiB requires extreme cases); pathological synthetic member lists in tests with enormous generated path names.

Related errors


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