can1357/oh-my-pi · error · ArchiveError
Invalid tar sparse real size
Error message
Invalid tar sparse real size
What it means
When a PAX record key is GNU.sparse.realsize (or GNU.sparse.size), its decimal value must fit within MAX_PAX_NUMERIC_BYTES (32) bytes. This throw fires when the sparse-file real-size value in a PAX header is longer than that cap — a value absurd for any real file, so the parser rejects it as corrupt.
Source
Thrown at packages/utils/src/ar/tar.ts:205
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");
if (bytesEqualAscii(key, "GNU.sparse.name")) {
attrs.set("GNU.sparse.name", readPaxPath(value, "PAX sparse path", limits));
} else if (bytesEqualAscii(key, "GNU.sparse.realsize") || bytesEqualAscii(key, "GNU.sparse.size")) {
if (value.byteLength > MAX_PAX_NUMERIC_BYTES) {
throw new ArchiveError("Invalid tar sparse real size");
}
attrs.set("GNU.sparse.realsize", TEXT_DECODER.decode(value));
}
} else if (bytesEqualAscii(key, "path") || bytesEqualAscii(key, "linkpath")) {
const field = bytesEqualAscii(key, "path") ? "PAX path" : "PAX link target";
attrs.set(field === "PAX path" ? "path" : "linkpath", readPaxPath(value, field, limits));
} else if (bytesEqualAscii(key, "size")) {
if (value.byteLength > MAX_PAX_NUMERIC_BYTES) throw new ArchiveError("Invalid tar member size");
attrs.set("size", TEXT_DECODER.decode(value));
}
}
pos += length;
}
return attrs;
}
function applyGlobalPax(globalPax: Map<string, string>, update: ReadonlyMap<string, string>): void {
for (const [key, value] of update) {View on GitHub (pinned to 9690622007)
Solutions
- Verify the archive with GNU tar (sparse archives are the least portable tar variant) and regenerate if corrupt.
- Avoid GNU sparse format when interoperability matters: repack with `tar --sparse=never` or plain storage.
- If writing sparse PAX headers yourself, ensure realsize values are plain decimal and realistically bounded.
- Catch ArchiveError and reject the archive; sparse members cannot be read by this library anyway (TarMemberSource throws for sparse data).
Example fix
// before $ tar cf sparse.tar --sparse=foo.bin // after $ tar cf foo.tar --sparse=never foo.bin
Defensive patterns
Strategy: fallback
Validate before calling
// GNU sparse PAX realsize must be decimal and <= 32 bytes long
function validSparseRealsize(value: string): boolean {
return value.length <= 32 && /^\d+$/.test(value);
} Try / catch
try {
const entries = readTarEntriesFromBuffer(buffer, options);
} catch (err) {
if (err instanceof ArchiveError && err.message === "Invalid tar sparse real size") {
throw new Error("Archive declares an impossible GNU sparse realsize; archive is corrupt or hostile");
}
throw err;
} Prevention
- Avoid GNU sparse tar format for interoperable archives — repack with --sparse=never.
- Note that sparse members cannot have their data read by this library regardless (it throws for sparse data), so store sparse files expanded.
- Treat oversized sparse-realsize values as a hostile-input signal and reject the archive.
- Validate sparse archives with GNU tar before processing.
When it happens
Trigger: Reading a tar containing a GNU sparse member whose PAX extended header has `GNU.sparse.realsize=<33+ digit string>` — parsed by parsePaxRecords inside readTarEntriesFromBuffer.
Common situations: Corrupted sparse archives, maliciously crafted sparse headers claiming impossible sizes, or archives produced by a broken sparse-aware writer.
Related errors
- Invalid tar ${field}
- Invalid tar PAX record
- Archive member '${formatArchivePathForError(memberPath)}' is
- Archive member '${formatArchivePathForError(name)}' is trunc
- Sealed frame too short
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e751a801e1b6d3c0.
Report an issue: GitHub.