can1357/oh-my-pi · error · ArchiveError

Invalid tar PAX record

Error message

Invalid tar PAX record

What it means

parsePaxRecords splits PAX extended-header data into '<length> <key>=<value>\n' records. This throw fires while reading the leading length token: there is no space after a non-empty token, the token is longer than 16 digits, or the record starts with a space. A well-formed PAX blob always begins each record with a decimal length followed by a space.

Source

Thrown at packages/utils/src/ar/tar.ts:182

	let signed = 0;
	for (let index = 0; index < BLOCK_SIZE; index++) {
		const inChecksum = index >= CHECKSUM_OFFSET && index < CHECKSUM_OFFSET + CHECKSUM_LENGTH;
		const byte = inChecksum ? 0x20 : (buffer[offset + index] ?? 0);
		unsigned += byte;
		signed += (byte << 24) >> 24;
	}
	return stored === unsigned || stored === signed;
}

function parsePaxRecords(data: Uint8Array, limits: ArchiveLimits): Map<string, string> {
	assertIndexSize(data.byteLength, limits, "tar PAX metadata");
	const attrs = new Map<string, string>();
	let pos = 0;
	while (pos < data.byteLength) {
		let space = pos;
		while (space < data.byteLength && data[space] !== 0x20) space++;
		if (space === pos || space >= data.byteLength || space - pos > 16) {
			throw new ArchiveError("Invalid tar PAX record");
		}
		let length = 0;
		for (let index = pos; index < space; index++) {
			const byte = data[index]!;
			if (byte < 0x30 || byte > 0x39) throw new ArchiveError("Invalid tar PAX record");
			length = length * 10 + (byte - 0x30);
			if (length > data.byteLength - pos) throw new ArchiveError("Invalid tar PAX record");
		}
		if (length <= 0 || pos + length > data.byteLength || data[pos + length - 1] !== 0x0a) {
			throw new ArchiveError("Invalid tar PAX record");
		}
		const record = data.subarray(space + 1, pos + length - 1);
		const equals = record.indexOf(0x3d);
		if (equals >= 0) {
			const key = record.subarray(0, equals);
			const value = record.subarray(equals + 1);
			if (bytesMatchAscii(key, 0, PAX_SPARSE_MARKER)) {
				attrs.set(PAX_SPARSE_MARKER, value.byteLength === 0 ? "" : "1");

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify archive integrity — this error usually means the PAX member bytes are corrupt or misaligned.
  2. Check the preceding header's size field: a wrong size there shifts data alignment and breaks PAX parsing.
  3. Regenerate the archive with GNU tar/bsdtar if a custom writer emitted it.
  4. Catch ArchiveError and reject the archive; PAX records cannot be partially recovered.
Defensive patterns

Strategy: try-catch

Validate before calling

// PAX payload must start with '<digits> ' per record
function looksLikePaxPayload(data: Uint8Array): boolean {
  const first = data[0];
  if (first === undefined || first === 0x20) return false; // empty/leading-space length
  return first >= 0x30 && first <= 0x39;
}

Try / catch

try {
  const entries = readTarEntriesFromBuffer(buffer, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message === "Invalid tar PAX record") {
    throw new Error("PAX extended header payload is malformed or misaligned");
  }
  throw err;
}

Prevention

When it happens

Trigger: Typeflag 'x'/'g' member whose payload does not start with `<digits> ` — e.g. payload begins with '=' (empty length), or a run of >16 non-space bytes — encountered while indexing via readTar/readTarEntriesFromBuffer.

Common situations: Corrupted archives, archives where PAX payload was truncated or shifted by an earlier bad size, or bytes that are not really PAX data being interpreted as such because a header typeflag was damaged.

Related errors


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