{"record":{"id":"e751a801e1b6d3c0","repo":"can1357/oh-my-pi","slug":"invalid-tar-sparse-real-size","errorCode":null,"errorMessage":"Invalid tar sparse real size","messagePattern":"Invalid tar sparse real size","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/tar.ts","lineNumber":205,"sourceCode":"\t\t\tif (byte < 0x30 || byte > 0x39) throw new ArchiveError(\"Invalid tar PAX record\");\n\t\t\tlength = length * 10 + (byte - 0x30);\n\t\t\tif (length > data.byteLength - pos) throw new ArchiveError(\"Invalid tar PAX record\");\n\t\t}\n\t\tif (length <= 0 || pos + length > data.byteLength || data[pos + length - 1] !== 0x0a) {\n\t\t\tthrow new ArchiveError(\"Invalid tar PAX record\");\n\t\t}\n\t\tconst record = data.subarray(space + 1, pos + length - 1);\n\t\tconst equals = record.indexOf(0x3d);\n\t\tif (equals >= 0) {\n\t\t\tconst key = record.subarray(0, equals);\n\t\t\tconst value = record.subarray(equals + 1);\n\t\t\tif (bytesMatchAscii(key, 0, PAX_SPARSE_MARKER)) {\n\t\t\t\tattrs.set(PAX_SPARSE_MARKER, value.byteLength === 0 ? \"\" : \"1\");\n\t\t\t\tif (bytesEqualAscii(key, \"GNU.sparse.name\")) {\n\t\t\t\t\tattrs.set(\"GNU.sparse.name\", readPaxPath(value, \"PAX sparse path\", limits));\n\t\t\t\t} else if (bytesEqualAscii(key, \"GNU.sparse.realsize\") || bytesEqualAscii(key, \"GNU.sparse.size\")) {\n\t\t\t\t\tif (value.byteLength > MAX_PAX_NUMERIC_BYTES) {\n\t\t\t\t\t\tthrow new ArchiveError(\"Invalid tar sparse real size\");\n\t\t\t\t\t}\n\t\t\t\t\tattrs.set(\"GNU.sparse.realsize\", TEXT_DECODER.decode(value));\n\t\t\t\t}\n\t\t\t} else if (bytesEqualAscii(key, \"path\") || bytesEqualAscii(key, \"linkpath\")) {\n\t\t\t\tconst field = bytesEqualAscii(key, \"path\") ? \"PAX path\" : \"PAX link target\";\n\t\t\t\tattrs.set(field === \"PAX path\" ? \"path\" : \"linkpath\", readPaxPath(value, field, limits));\n\t\t\t} else if (bytesEqualAscii(key, \"size\")) {\n\t\t\t\tif (value.byteLength > MAX_PAX_NUMERIC_BYTES) throw new ArchiveError(\"Invalid tar member size\");\n\t\t\t\tattrs.set(\"size\", TEXT_DECODER.decode(value));\n\t\t\t}\n\t\t}\n\t\tpos += length;\n\t}\n\treturn attrs;\n}\n\nfunction applyGlobalPax(globalPax: Map<string, string>, update: ReadonlyMap<string, string>): void {\n\tfor (const [key, value] of update) {","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/tar.ts#L187-L223","documentation":"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.","triggerScenarios":"Reading a tar containing a GNU sparse member whose PAX extended header has `GNU.sparse.realsize=<33+ digit string>` — parsed by parsePaxRecords inside readTarEntriesFromBuffer.","commonSituations":"Corrupted sparse archives, maliciously crafted sparse headers claiming impossible sizes, or archives produced by a broken sparse-aware writer.","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)."],"exampleFix":"// before\n$ tar cf sparse.tar --sparse=foo.bin\n// after\n$ tar cf foo.tar --sparse=never foo.bin","handlingStrategy":"fallback","validationCode":"// GNU sparse PAX realsize must be decimal and <= 32 bytes long\nfunction validSparseRealsize(value: string): boolean {\n  return value.length <= 32 && /^\\d+$/.test(value);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const entries = readTarEntriesFromBuffer(buffer, options);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message === \"Invalid tar sparse real size\") {\n    throw new Error(\"Archive declares an impossible GNU sparse realsize; archive is corrupt or hostile\");\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["tar","pax","sparse-files","gnu-tar","malformed-data"],"backgroundTag":"corrupt-tar-archive","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}