can1357/oh-my-pi · error · ArchiveError

Invalid ar archive BSD extended name length

Error message

Invalid ar archive BSD extended name length

What it means

For BSD-style extended names ('#1/<len>'), parseHeader extracts the length digits from the raw name field and validates them: all digits, a safe integer, strictly positive, and not larger than the member's physical size (the name is stored at the start of the member data, so it can't exceed it). This first throw fires when the text after '#1/' is not purely digits.

Source

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

	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);
	const mtimeSeconds = parseOptionalNumber(decodeAsciiField(header, 16, 12), 10, "modification time");
	parseOptionalNumber(decodeAsciiField(header, 28, 6), 10, "user id");
	parseOptionalNumber(decodeAsciiField(header, 34, 6), 10, "group id");
	const mode = parseOptionalNumber(decodeAsciiField(header, 40, 8), 8, "mode");
	const physicalSize = parseRequiredSize(decodeAsciiField(header, 48, 10));
	let bsdNameLength: number | undefined;
	if (rawName.startsWith("#1/")) {
		const encodedLength = rawName.slice(3);
		if (!/^\d+$/.test(encodedLength)) throw new ArchiveError("Invalid ar archive BSD extended name length");
		bsdNameLength = Number.parseInt(encodedLength, 10);
		if (!Number.isSafeInteger(bsdNameLength) || bsdNameLength <= 0 || bsdNameLength > physicalSize) {
			throw new ArchiveError("Invalid ar archive BSD extended name length");
		}
	}
	return { rawName, physicalSize, mtimeSeconds, mode, bsdNameLength };
}

function decodeName(bytes: Uint8Array, limits: ArchiveLimits): string {
	assertArchivePathBytes(bytes.byteLength, "member path", limits.maxPathBytes);
	return UTF8_DECODER.decode(bytes);
}

function decodeBsdName(bytes: Uint8Array, limits: ArchiveLimits): { name: string; byteLength: number } {
	const nul = bytes.indexOf(0);
	const nameBytes = nul >= 0 ? bytes.subarray(0, nul) : bytes;
	if (nameBytes.byteLength === 0) throw new ArchiveError("Invalid ar archive empty BSD extended name");
	return { name: decodeName(nameBytes, limits), byteLength: nameBytes.byteLength };

View on GitHub (pinned to 9690622007)

Solutions

  1. Confirm the producer is BSD ar and the '#1/' encoding is intended; regenerate with consistent tooling (llvm-ar / GNU ar) for cross-platform compatibility
  2. Hex-dump the name field (bytes 0-15) and check what follows '#1/'
  3. Rename files starting with '#1/' in the producer or escape them via the intended encoding
  4. Ensure the writer stores the 4-byte length in the member data as BSD ar does for #1/ names

Example fix

// before: malformed BSD name field
rawName = '#1/ 12'      // digits check fails on the space
// after: correct BSD form
rawName = '#1/12       ' // decoded length digits '12'
Defensive patterns

Strategy: validation

Validate before calling

function bsdNamePrefixIsValid(rawName: string): boolean {
  if (!rawName.startsWith('#1/')) return true; // not a BSD long name
  return /^\d+$/.test(rawName.slice(3));
}
if (!bsdNamePrefixIsValid(rawNameField)) throw new Error('malformed #1/ BSD name');

Type guard

function isBsdLongNameRef(rawName: string): boolean {
  return /^#1\/\d+$/.test(rawName);
}

Try / catch

try {
  const names = await archive.list();
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('BSD extended name length')) {
    // archive mixes BSD naming unexpectedly — inspect with ar t / llvm-ar t
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing an archive whose member rawName starts with '#1/' followed by non-digit characters — e.g. '#1/abc' or '#1/' with trailing content, or a name coincidentally beginning with '#1/' in a non-BSD archive.

Common situations: Archives from BSD ar (macOS) parsed where the GNU convention was expected; custom writers emitting '#1/' prefixes incorrectly; filenames that literally start with '#1/' written without BSD long-name encoding.

Related errors


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