can1357/oh-my-pi · error · ArchiveError
Invalid ar archive: truncated member data
Error message
Invalid ar archive: truncated member data
What it means
After parsing a member header, header.physicalSize implied a payload end beyond the available bytes (or a non-safe integer). The member's data region is cut off, so the record cannot be represented and the archive is rejected.
Source
Thrown at packages/utils/src/ar/unix-ar.ts:209
if (!sniffUnixAr(bytes)) throw new ArchiveError("Invalid ar archive signature");
}
/** Parse a fully materialized Unix ar archive for composition by formats such as deb. */
export function readUnixArEntriesFromBuffer(bytes: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[] {
readSignatureFromBuffer(bytes);
const records: RawArMember[] = [];
let longNames: Uint8Array | undefined;
let metadataSize = 0;
for (let position = SIGNATURE.length; position < bytes.byteLength; ) {
if (bytes.byteLength - position < HEADER_SIZE)
throw new ArchiveError("Invalid ar archive: truncated member header");
const header = parseHeader(readMemoryRange(bytes, position, position + HEADER_SIZE));
metadataSize += HEADER_SIZE;
assertIndexSize(metadataSize, options.limits, "index");
const payloadOffset = position + HEADER_SIZE;
const payloadEnd = payloadOffset + header.physicalSize;
if (!Number.isSafeInteger(payloadEnd) || payloadEnd > bytes.byteLength) {
throw new ArchiveError("Invalid ar archive: truncated member data");
}
let name = header.rawName;
let nameByteLength = Buffer.byteLength(name, "utf-8");
let dataOffset = payloadOffset;
let size = header.physicalSize;
if (header.bsdNameLength !== undefined) {
metadataSize += header.bsdNameLength;
assertIndexSize(metadataSize, options.limits, "index");
const nameBytes = readMemoryRange(bytes, payloadOffset, payloadOffset + header.bsdNameLength);
const decoded = decodeBsdName(nameBytes, options.limits);
name = decoded.name;
nameByteLength = decoded.byteLength;
dataOffset += header.bsdNameLength;
size -= header.bsdNameLength;
} else if (header.rawName === "//") {
metadataSize += header.physicalSize;
assertIndexSize(metadataSize, options.limits, "index");
longNames = readMemoryRange(bytes, payloadOffset, payloadEnd);View on GitHub (pinned to 9690622007)
Solutions
- Re-download/rebuild the archive and verify checksums; the data is genuinely cut off.
- Check the size field of the last header with a hex editor if you must salvage; fix or extract with GNU ar.
- Ensure the producing tool wrote the correct padded size (BSD ar pads extended names to even lengths).
- Pre-compute expected archive size from members when generating, and compare before parsing.
Example fix
// before: trusting header size blindly when salvaging
const entries = await readUnixAr(untrustedBytes);
// after: verify size field plausibility first
const size = view.getBigUint64(offset, true); // inspect header size
if (size > BigInt(untrustedBytes.byteLength)) throw new Error('oversized member size'); Defensive patterns
Strategy: validation
Validate before calling
// plausible sanity: last 60-byte header's size must fit within the file
const lastHeader = bytes.byteLength - 60;
if (lastHeader >= 8) {
const sizeText = new TextDecoder().decode(bytes.subarray(lastHeader + 48, lastHeader + 58)).trim();
const size = Number(sizeText);
if (Number.isFinite(size) && 8 + lastHeader + 60 + size > bytes.byteLength) {
throw new Error('archive truncated: final member data incomplete');
}
} Try / catch
try {
return await readUnixAr(source);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('truncated member data')) {
throw new Error(`archive member data cut off — file incomplete or corrupt`);
}
throw err;
} Prevention
- Compare download size to Content-Length/publisher checksum before parsing.
- Validate archives produced by your own writer with `ar t` in CI.
- Guard against absurd size fields when ingesting untrusted archives.
- Use resumable downloads that retry until the full byte count arrives.
When it happens
Trigger: A member header's size field claims more data than exists (truncated archive, or a corrupted/huge size field like 0xFFFFFFFFFFFFFFFF that breaks Number.isSafeInteger after offset addition).
Common situations: Interrupted downloads; archives written with a wrong size field by a buggy tool; corrupted size bytes; mixing ar variants where BSD extended names shift offsets.
Related errors
- Invalid ar archive: truncated member header
- Invalid ar archive ${field}
- Invalid ar archive member size
- Invalid ar archive member header
- Invalid ar archive BSD extended name length
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/56511fb886faa1e9.
Report an issue: GitHub.