{"record":{"id":"140c800271feea4d","repo":"can1357/oh-my-pi","slug":"invalid-ar-archive-member-size","errorCode":null,"errorMessage":"Invalid ar archive member size","messagePattern":"Invalid ar archive member size","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/unix-ar.ts","lineNumber":71,"sourceCode":"\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;\n}\n\nfunction parseHeader(header: Uint8Array): {\n\trawName: string;\n\tphysicalSize: number;\n\tmtimeSeconds?: number;\n\tmode?: number;\n\tbsdNameLength?: number;\n} {\n\tif (\n\t\theader.byteLength !== HEADER_SIZE ||\n\t\theader[HEADER_TRAILER_OFFSET] !== 0x60 ||\n\t\theader[HEADER_TRAILER_OFFSET + 1] !== 0x0a\n\t) {\n\t\tthrow new ArchiveError(\"Invalid ar archive member header\");\n\t}\n\tconst rawName = decodeAsciiField(header, 0, NAME_SIZE);","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/unix-ar.ts#L53-L89","documentation":"parseRequiredSize parses the 10-byte member size field (decimal) via parseOptionalNumber; if that returns undefined — the field was empty or the '-1' sentinel — parseRequiredSize throws this error. A member's size is mandatory: without it the parser cannot locate the member's data or the next header.","triggerScenarios":"Parsing a member header whose size slot (bytes 48-57) is all spaces or literally '-1', via parseHeader; typically a zeroed or blank-padded header region.","commonSituations":"Truncated archives where a partial header was zero/space filled; archives concatenated with padding blocks; buggy writers that emit an empty size for empty members (they should write '0').","solutions":["Write '0' (not blanks) for zero-length members in the producer","Hex-dump the header at the failing offset and confirm bytes 48-57 contain a decimal size","Regenerate the archive with standard ar tooling","Scan the file for runs of 0x20/0x00 to locate the truncation point"],"exampleFix":"// before: blank size field for empty member\n'          '\n// after: explicit zero size\n'0         '","handlingStrategy":"validation","validationCode":"function hasMemberSize(header: Uint8Array): boolean {\n  const size = new TextDecoder().decode(header.subarray(48, 58)).trim();\n  return /^\\d+$/.test(size); // '' and '-1' are rejected upstream\n}\nif (!hasMemberSize(header)) throw new Error('archive header missing size field');","typeGuard":"function isPresentArSize(value: string): boolean {\n  return /^\\d+$/.test(value);\n}","tryCatchPattern":"try {\n  await archive.extractAll(dest);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message === 'Invalid ar archive member size') {\n    // treat file as corrupt: reject download, request re-upload\n  } else throw err;\n}","preventionTips":["Write '0' for zero-length members, never blanks","Verify header trailer bytes 58-59 are 0x60 0x0a in the producer","Round-trip parse archives right after generation","Reject truncated transfers with a size check before parsing"],"tags":["archive","parsing","ar-format","corrupt-file"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}