can1357/oh-my-pi · error · ArchiveError
Invalid ar archive ${field}
Error message
Invalid ar archive ${field} What it means
This ArchiveError is thrown by parseOptionalNumber in packages/utils/src/ar/unix-ar.ts when a numeric header field (mode, mtime, uid, gid) contains characters invalid for the expected radix — octal fields must match /^[0-7]+$/, decimal /^\d+$/, and empty or '-1' (the GNU 'unknown' sentinel) is treated as absent. So this throw means the field is present but malformed. The library throws rather than guessing so corrupt archives are rejected deterministically.
Source
Thrown at packages/utils/src/ar/unix-ar.ts:63
}
}
function decodeAsciiField(bytes: Uint8Array, offset: number, length: number): string {
let end = offset + length;
while (end > offset && bytes[end - 1] === 0x20) end--;
let value = "";
for (let index = offset; index < end; index++) {
const byte = bytes[index]!;
if (byte < 0x20 || byte > 0x7e) throw new ArchiveError("Invalid ar archive header field");
value += String.fromCharCode(byte);
}
return value;
}
function parseOptionalNumber(value: string, radix: 8 | 10, field: string): number | undefined {
if (value === "" || value === "-1") return undefined;
const pattern = radix === 8 ? /^[0-7]+$/ : /^\d+$/;
if (!pattern.test(value)) throw new ArchiveError(`Invalid ar archive ${field}`);
const parsed = Number.parseInt(value, radix);
if (!Number.isSafeInteger(parsed)) throw new ArchiveError(`Invalid ar archive ${field}`);
return parsed;
}
function parseRequiredSize(value: string): number {
const parsed = parseOptionalNumber(value, 10, "member size");
if (parsed === undefined) throw new ArchiveError("Invalid ar archive member size");
return parsed;
}
function parseHeader(header: Uint8Array): {
rawName: string;
physicalSize: number;
mtimeSeconds?: number;
mode?: number;
bsdNameLength?: number;
} {View on GitHub (pinned to 9690622007)
Solutions
- Hex-dump the 60-byte member header and verify fields 16-27 (mtime), 28-33 (uid), 34-39 (gid), 40-47 (mode) hold only ASCII digits (0-7 for mode), space-padded
- Regenerate the archive with a standard tool (ar, llvm-ar) instead of custom writer code
- If you control the writer, space-pad numeric fields to their fixed width
- Re-download or restore the archive if corruption in transit is suspected
Example fix
// before: sign-padded mode field '-644 ' // after: valid octal, space-padded '644 '
Defensive patterns
Strategy: validation
Validate before calling
const dec = new TextDecoder();
function checkNumericField(header: Uint8Array, start: number, len: number, radix: 8 | 10): boolean {
const s = dec.decode(header.subarray(start, start + len)).trim();
return s === '' || s === '-1' || (radix === 8 ? /^[0-7]+$/.test(s) : /^\d+$/.test(s));
}
// before parsing: mtime, uid, gid, mode slots must all pass
const ok = checkNumericField(header, 16, 12, 10) && checkNumericField(header, 28, 6, 10)
&& checkNumericField(header, 34, 6, 10) && checkNumericField(header, 40, 8, 8); Type guard
function isArNumericField(value: string, radix: 8 | 10): boolean {
return value === '' || value === '-1' || (radix === 8 ? /^[0-7]+$/.test(value) : /^\d+$/.test(value));
} Try / catch
import { ArchiveError } from '@oh-my-pi/pi-utils';
try {
await archive.list();
} catch (err) {
if (err instanceof ArchiveError && err.message.startsWith('Invalid ar archive')) {
// quarantine file, fall back to raw-bytes inspection
} else throw err;
} Prevention
- Always space-pad numeric header fields to their fixed widths
- Use octal for mode, decimal for mtime/uid/gid
- Never digit-fill or sign-pad slots; pad with 0x20
- Prefer standard ar/llvm-ar over custom writers
- Checksum-verify archives from network sources before parsing
When it happens
Trigger: Parsing an ar member whose 6-byte uid, 6-byte gid, 8-byte mode, or 12-byte mtime header slots contain non-digit bytes (non-padding spaces, letters, or negatives other than '-1') via parseHeader, reached through any archive listing/extraction API.
Common situations: Hand-edited or truncated .a/.deb archives; broken custom writers that use sign characters or zero-padding instead of space-padding; decimal values written into the octal mode slot; corrupted downloads.
Related errors
- Invalid ARJ ${field}: missing terminator
- Invalid ar archive member size
- Invalid ar archive member header
- Invalid ar archive BSD extended name length
- Invalid ar archive empty BSD extended name
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d61dd536a6ec7ef8.
Report an issue: GitHub.