can1357/oh-my-pi · error · ArchiveError

Invalid tar numeric field

Error message

Invalid tar numeric field

What it means

readTarNumeric decodes tar header numeric fields (octal text or GNU base-256 binary) from the archive buffer. This throw means the requested field does not fit inside the buffer at all (negative offset, non-positive length, or offset+length past the end of the bytes). The library throws instead of reading out-of-bounds because the header block is truncated or the caller supplied a bad offset.

Source

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

		bytesMatchAscii(buffer, offset + MAGIC_OFFSET, MAGIC) && bytesMatchAscii(buffer, offset + VERSION_OFFSET, VERSION)
	);
}

function readMetadataPath(data: Uint8Array, field: string, limits: ArchiveLimits): string {
	const nul = data.indexOf(0);
	const value = data.subarray(0, nul === -1 ? data.byteLength : nul);
	assertArchivePathBytes(value.byteLength, field, limits.maxPathBytes);
	return TEXT_DECODER.decode(value);
}

function readPaxPath(data: Uint8Array, field: string, limits: ArchiveLimits): string {
	assertArchivePathBytes(data.byteLength, field, limits.maxPathBytes);
	return TEXT_DECODER.decode(data);
}

function readTarNumeric(buffer: Uint8Array, offset: number, length: number): number {
	if (offset < 0 || length <= 0 || offset + length > buffer.byteLength) {
		throw new ArchiveError("Invalid tar numeric field");
	}
	const first = buffer[offset]!;
	let value = 0n;
	if ((first & 0x80) !== 0) {
		value = BigInt(first & 0x7f);
		for (let index = 1; index < length; index++) {
			value = (value << 8n) | BigInt(buffer[offset + index]!);
		}
		if ((first & 0x40) !== 0) value -= 1n << BigInt(length * 8 - 1);
	} else {
		for (let index = 0; index < length; index++) {
			const byte = buffer[offset + index]!;
			if (byte >= 0x30 && byte <= 0x37) value = value * 8n + BigInt(byte - 0x30);
		}
	}
	return Number(value);
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the input is a complete tar buffer (at least one 512-byte block) before parsing; use sniffTar to detect the format first.
  2. Check where the offset/length arguments come from — an earlier miscomputed size or offset in your own code is the usual culprit.
  3. Re-download or re-extract the archive; a truncated file cannot be repaired by the parser.
  4. Wrap the parse in try-catch on ArchiveError and surface 'corrupt/truncated tar archive' to the user.

Example fix

// before
const size = readTarNumeric(truncatedChunk, 124, 12); // throws
// after
if (truncatedChunk.byteLength < 512) throw new Error("tar buffer too small");
const size = readTarNumeric(truncatedChunk, 124, 12);
Defensive patterns

Strategy: validation

Validate before calling

import { sniffTar } from "@oh-my-pi/pi-utils/ar/tar";
if (buffer.byteLength < 512 || !sniffTar(buffer)) {
  throw new Error("Input is not a complete tar archive");
}

Try / catch

try {
  const entries = readTarEntriesFromBuffer(buffer, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message === "Invalid tar numeric field") {
    throw new Error("Tar buffer truncated or misaligned: header field out of bounds");
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling readTarNumeric (via the size/stored/mtime/rawMode accessors of a tar member) on a buffer shorter than the field requires — e.g. a buffer < 512 bytes passed where a full tar header block is expected, or an offset computed past buffer end.

Common situations: Feeding a truncated download (partial tar), a buffer sliced at the wrong offset, sniffing a file smaller than one 512-byte block, or passing non-tar bytes to a helper that trusts a size field.

Related errors


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