{"record":{"id":"b8d830d821c0b9b1","repo":"can1357/oh-my-pi","slug":"invalid-ar-archive-header-field","errorCode":null,"errorMessage":"Invalid ar archive header field","messagePattern":"Invalid ar archive header field","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/unix-ar.ts","lineNumber":54,"sourceCode":"\t\t\tconst bytes = await this.#source.read(this.#offset, this.#offset + size);\n\t\t\tif (bytes.byteLength !== size) {\n\t\t\t\tthrow new ArchiveError(`Archive member '${memberPath}' is truncated`);\n\t\t\t}\n\t\t\treturn bytes;\n\t\t} catch (error) {\n\t\t\tif (error instanceof ArchiveError) throw error;\n\t\t\tthrow new ArchiveError(error instanceof Error ? error.message : String(error));\n\t\t}\n\t}\n}\n\nfunction decodeAsciiField(bytes: Uint8Array, offset: number, length: number): string {\n\tlet end = offset + length;\n\twhile (end > offset && bytes[end - 1] === 0x20) end--;\n\tlet value = \"\";\n\tfor (let index = offset; index < end; index++) {\n\t\tconst byte = bytes[index]!;\n\t\tif (byte < 0x20 || byte > 0x7e) throw new ArchiveError(\"Invalid ar archive header field\");\n\t\tvalue += String.fromCharCode(byte);\n\t}\n\treturn value;\n}\n\nfunction parseOptionalNumber(value: string, radix: 8 | 10, field: string): number | undefined {\n\tif (value === \"\" || value === \"-1\") return undefined;\n\tconst pattern = radix === 8 ? /^[0-7]+$/ : /^\\d+$/;\n\tif (!pattern.test(value)) throw new ArchiveError(`Invalid ar archive ${field}`);\n\tconst parsed = Number.parseInt(value, radix);\n\tif (!Number.isSafeInteger(parsed)) throw new ArchiveError(`Invalid ar archive ${field}`);\n\treturn parsed;\n}\n\nfunction parseRequiredSize(value: string): number {\n\tconst parsed = parseOptionalNumber(value, 10, \"member size\");\n\tif (parsed === undefined) throw new ArchiveError(\"Invalid ar archive member size\");\n\treturn parsed;","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/unix-ar.ts#L36-L72","documentation":"ar header fields are fixed-width ASCII. decodeAsciiField trims trailing spaces and validates every remaining byte is printable ASCII (0x20–0x7e); any control byte or high-bit/non-ASCII byte makes the header unparsable, so the library throws. Called for name, mode, mtime, and size fields.","triggerScenarios":"Reading a file that isn't a valid ar archive (wrong magic, binary blob renamed to .a), a corrupted header, or a non-GNU/non-BSD ar variant with binary header fields.","commonSituations":"Passing a .tar, .zip, or object file (.o is actually valid ar — but a plain ELF binary is not) to the ar parser; truncated download landing on a header; byte-shifted reads after a bad offset.","solutions":["Verify the input is actually an ar archive (global magic '!<arch>\\n') before parsing","Re-download/restore the file and check its checksum","Use a parser matching the archive's dialect (GNU vs BSD long-name tables)"],"exampleFix":"// before\nconst ar = await ArReader.create(Bun.file(maybeTar));\n// after\nconst head = new Uint8Array(await Bun.file(maybeTar).slice(0, 8).arrayBuffer());\nif (new TextDecoder().decode(head) !== \"!<arch>\\n\") {\n\tthrow new Error(\"Not an ar archive\");\n}\nconst ar = await ArReader.create(Bun.file(maybeTar));","handlingStrategy":"validation","validationCode":"const MAGIC = \"!<arch>\\n\";\nconst head = new TextDecoder(\"latin1\").decode(await file.slice(0, 8).arrayBuffer());\nif (head !== MAGIC) throw new Error(`Not an ar archive (got ${JSON.stringify(head)})`);","typeGuard":null,"tryCatchPattern":"try {\n\tconst ar = await ArReader.create(source);\n} catch (err) {\n\tif (err instanceof ArchiveError && err.message === \"Invalid ar archive header field\") {\n\t\t// input is not a valid ar archive or is corrupted\n\t}\n\tthrow err;\n}","preventionTips":["Sniff the '!<arch>\\n' magic before handing a file to the ar parser","Verify file integrity (checksum/size) after transfer","Don't feed tar/zip/ELF binaries to the ar reader"],"tags":["archive","ar","header-parsing"],"backgroundTag":"invalid-archive-header-field","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}