{"record":{"id":"8bc66662a0684aee","repo":"can1357/oh-my-pi","slug":"invalid-ar-archive-signature","errorCode":null,"errorMessage":"Invalid ar archive signature","messagePattern":"Invalid ar archive signature","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/unix-ar.ts","lineNumber":191,"sourceCode":"\t\tconst entry: ArchiveIndexEntry = {\n\t\t\tpath,\n\t\t\tisDirectory,\n\t\t\tsize: isDirectory ? 0 : record.size,\n\t\t\t...(record.mtimeSeconds !== undefined ? { mtimeMs: record.mtimeSeconds * 1000 } : {}),\n\t\t\t...(record.mode !== undefined ? { mode: record.mode } : {}),\n\t\t\t...(!isDirectory\n\t\t\t\t? { storage: { type: \"member\" as const, source: new ArMemberSource(source, record.dataOffset) } }\n\t\t\t\t: {}),\n\t\t};\n\t\tupsertArchiveEntry(entries, entry);\n\t\tassertEntryCount(entries.size, options.limits);\n\t}\n\tensureParentDirectories(entries, options.limits);\n\treturn [...entries.values()];\n}\n\nfunction readSignatureFromBuffer(bytes: Uint8Array): void {\n\tif (!sniffUnixAr(bytes)) throw new ArchiveError(\"Invalid ar archive signature\");\n}\n\n/** Parse a fully materialized Unix ar archive for composition by formats such as deb. */\nexport function readUnixArEntriesFromBuffer(bytes: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[] {\n\treadSignatureFromBuffer(bytes);\n\tconst records: RawArMember[] = [];\n\tlet longNames: Uint8Array | undefined;\n\tlet metadataSize = 0;\n\tfor (let position = SIGNATURE.length; position < bytes.byteLength; ) {\n\t\tif (bytes.byteLength - position < HEADER_SIZE)\n\t\t\tthrow new ArchiveError(\"Invalid ar archive: truncated member header\");\n\t\tconst header = parseHeader(readMemoryRange(bytes, position, position + HEADER_SIZE));\n\t\tmetadataSize += HEADER_SIZE;\n\t\tassertIndexSize(metadataSize, options.limits, \"index\");\n\t\tconst payloadOffset = position + HEADER_SIZE;\n\t\tconst payloadEnd = payloadOffset + header.physicalSize;\n\t\tif (!Number.isSafeInteger(payloadEnd) || payloadEnd > bytes.byteLength) {\n\t\t\tthrow new ArchiveError(\"Invalid ar archive: truncated member data\");","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/unix-ar.ts#L173-L209","documentation":"The input buffer does not begin with the Unix ar global magic ('!<arch>\\n' / SIGNATURE). readSignatureFromBuffer runs before any member parsing and is the first structural validation, so this error means the file is not an ar archive at all.","triggerScenarios":"Calling readUnixAr/readUnixArEntriesFromBuffer on a non-ar file: a tarball, .zip, text file, or an empty/1-byte file. sniffUnixAr returns false on the first bytes.","commonSituations":"Wrong file passed to a deb-composition path; a file with an .a/.deb extension that is actually a different format; HTML error page saved instead of a download; truncated download leaving fewer bytes than the signature.","solutions":["Verify the file is really an ar archive: `file archive.a` should say 'current ar archive'.","Check the first 8 bytes yourself for '!<arch>\\n' before calling, to give a better error.","Re-download the artifact; compare its size/hash with the publisher's checksum.","Route the file to the correct parser (tar/zip) if it is another format."],"exampleFix":"// before\nconst entries = await readUnixAr(bytes);\n// after: sniff first\nimport { sniffUnixAr } from \"@oh-my-pi/pi-utils\";\nif (!sniffUnixAr(bytes)) throw new Error(`${path} is not an ar archive`);\nconst entries = await readUnixAr(bytes);","handlingStrategy":"validation","validationCode":"import { sniffUnixAr } from \"@oh-my-pi/pi-utils\";\nif (!sniffUnixAr(bytes)) throw new Error(`${label}: not an ar archive (missing !<arch>\\n magic)`);","typeGuard":"function isArMagic(head: Uint8Array): boolean {\n  const magic = [0x21, 0x3c, 0x61, 0x72, 0x63, 0x68, 0x3e, 0x0a];\n  return head.length >= 8 && magic.every((b, i) => head[i] === b);\n}","tryCatchPattern":"try {\n  return await readUnixArEntriesFromBuffer(bytes, opts);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('signature')) {\n    throw new Error(`${label}: not a Unix ar archive`);\n  }\n  throw err;\n}","preventionTips":["Sniff the magic bytes before dispatching a file to any archive parser.","Verify downloads against size/hash before parsing.","Use `file`/extension checks at ingest boundaries.","Keep format dispatch in one place so .deb/.a files never fall through to the wrong reader."],"tags":["archive","ar-format","invalid-input","parsing"],"backgroundTag":"invalid-archive-signature","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}