{"record":{"id":"fb311a462bc67a3a","repo":"can1357/oh-my-pi","slug":"invalid-ar-archive-member-name-reference","errorCode":null,"errorMessage":"Invalid ar archive member name '${reference}'","messagePattern":"Invalid ar archive member name '(.+?)'","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/unix-ar.ts","lineNumber":130,"sourceCode":"function decodeBsdName(bytes: Uint8Array, limits: ArchiveLimits): { name: string; byteLength: number } {\n\tconst nul = bytes.indexOf(0);\n\tconst nameBytes = nul >= 0 ? bytes.subarray(0, nul) : bytes;\n\tif (nameBytes.byteLength === 0) throw new ArchiveError(\"Invalid ar archive empty BSD extended name\");\n\treturn { name: decodeName(nameBytes, limits), byteLength: nameBytes.byteLength };\n}\n\nfunction shortName(rawName: string): string {\n\tif (rawName === \"/\" || rawName === \"//\" || rawName === \"/SYM64/\") return rawName;\n\treturn rawName.endsWith(\"/\") ? rawName.slice(0, -1) : rawName;\n}\n\nfunction resolveLongName(\n\treference: string,\n\ttable: Uint8Array,\n\tlimits: ArchiveLimits,\n): { name: string; byteLength: number } {\n\tconst offsetText = reference.slice(1);\n\tif (!/^\\d+$/.test(offsetText)) throw new ArchiveError(`Invalid ar archive member name '${reference}'`);\n\tconst offset = Number.parseInt(offsetText, 10);\n\tif (!Number.isSafeInteger(offset) || offset < 0 || offset >= table.byteLength) {\n\t\tthrow new ArchiveError(`Invalid ar archive long-name offset '${reference}'`);\n\t}\n\tlet end = offset;\n\twhile (end < table.byteLength && table[end] !== 0 && table[end] !== 0x0a) end++;\n\tif (end === table.byteLength) throw new ArchiveError(`Unterminated ar archive long name at offset ${offset}`);\n\tlet nameEnd = end;\n\tif (table[end] === 0x0a && nameEnd > offset && table[nameEnd - 1] === 0x2f) nameEnd--;\n\tif (nameEnd === offset) throw new ArchiveError(`Empty ar archive long name at offset ${offset}`);\n\tconst nameBytes = table.subarray(offset, nameEnd);\n\treturn { name: decodeName(nameBytes, limits), byteLength: nameBytes.byteLength };\n}\n\nfunction isMetadataName(name: string): boolean {\n\treturn name === \"/\" || name === \"//\" || name === \"/SYM64/\" || name === \"__.SYMDEF\" || name === \"__.SYMDEF SORTED\";\n}\n","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/unix-ar.ts#L112-L148","documentation":"resolveLongName handles GNU-style long names stored as '/<offset>' into the string table ('//') member. This throw fires when the text after '/' is not all digits — the member name looks like a long-name reference but the offset is malformed. The library treats this as corruption rather than a literal name, since GNU ar never writes a non-numeric '/...' name.","triggerScenarios":"Parsing an archive where a member's rawName is '/xyz', '/12a', '/ 5', or similar non-numeric form; or a '/'-prefixed special name mistyped by a custom writer.","commonSituations":"Custom archive writers emitting '/name' instead of storing names in the '// ' table; corruption of the 16-byte name field; mixing GNU naming conventions with incompatible tooling.","solutions":["Hex-dump the name field (bytes 0-15) of the failing member","Fix the producer to store long names in the '// ' string table and reference them as '/<decimal offset>'","Regenerate the archive with GNU ar or llvm-ar","If a member name legitimately starts with '/', encode it via the long-name table rather than literally"],"exampleFix":"// before: literal '/myname' in name field\nname = '/myname'\n// after: put in string table, reference by offset\nnameField = '/' + String(tableOffset).padEnd(15); // e.g. '0              '","handlingStrategy":"validation","validationCode":"function nameFieldIsValid(rawName: string): boolean {\n  if (rawName === '/' || rawName === '//' || rawName === '/SYM64/') return true;\n  if (rawName.startsWith('/')) return /^\\/\\d+$/.test(rawName);\n  return true;\n}\n// scan member name fields (16-byte slots) before parsing","typeGuard":"function isLongNameReference(rawName: string): boolean {\n  return /^\\/\\d+$/.test(rawName);\n}","tryCatchPattern":"try {\n  const entries = await archive.list();\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.startsWith(\"Invalid ar archive member name '\")) {\n    // log offending reference from the message; inspect with ar t\n  } else throw err;\n}","preventionTips":["Store long names in the '// ' table; reference as '/<offset>' only","Never write literal '/name' into the name field","Keep GNU naming conventions if targeting GNU ar readers","Add a writer unit test that round-trips a long filename"],"tags":["archive","parsing","ar-format","gnu","naming"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}