can1357/oh-my-pi · error · ArchiveError

Invalid ar archive member size

Error message

Invalid ar archive member size

What it means

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.

Source

Thrown at packages/utils/src/ar/unix-ar.ts:71

		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;
} {
	if (
		header.byteLength !== HEADER_SIZE ||
		header[HEADER_TRAILER_OFFSET] !== 0x60 ||
		header[HEADER_TRAILER_OFFSET + 1] !== 0x0a
	) {
		throw new ArchiveError("Invalid ar archive member header");
	}
	const rawName = decodeAsciiField(header, 0, NAME_SIZE);

View on GitHub (pinned to 9690622007)

Solutions

  1. Write '0' (not blanks) for zero-length members in the producer
  2. Hex-dump the header at the failing offset and confirm bytes 48-57 contain a decimal size
  3. Regenerate the archive with standard ar tooling
  4. Scan the file for runs of 0x20/0x00 to locate the truncation point

Example fix

// before: blank size field for empty member
'          '
// after: explicit zero size
'0         '
Defensive patterns

Strategy: validation

Validate before calling

function hasMemberSize(header: Uint8Array): boolean {
  const size = new TextDecoder().decode(header.subarray(48, 58)).trim();
  return /^\d+$/.test(size); // '' and '-1' are rejected upstream
}
if (!hasMemberSize(header)) throw new Error('archive header missing size field');

Type guard

function isPresentArSize(value: string): boolean {
  return /^\d+$/.test(value);
}

Try / catch

try {
  await archive.extractAll(dest);
} catch (err) {
  if (err instanceof ArchiveError && err.message === 'Invalid ar archive member size') {
    // treat file as corrupt: reject download, request re-upload
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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').

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/140c800271feea4d. Report an issue: GitHub.