can1357/oh-my-pi · error · ArchiveError

Ar archive member '${name}' references a missing long-name t

Error message

Ar archive member '${name}' references a missing long-name table

What it means

A member header uses the '/NNN' long-name convention, but no '//' long-name table member was seen earlier in the archive. Without the table the name cannot be resolved, so the reader rejects the archive rather than fabricating a name.

Source

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

	return { name: decodeName(nameBytes, limits), byteLength: nameBytes.byteLength };
}

function isMetadataName(name: string): boolean {
	return name === "/" || name === "//" || name === "/SYM64/" || name === "__.SYMDEF" || name === "__.SYMDEF SORTED";
}

function materializeEntries(
	records: RawArMember[],
	longNames: Uint8Array | undefined,
	source: ByteSource,
	options: FormatReadOptions,
): ArchiveIndexEntry[] {
	const entries = new Map<string, ArchiveIndexEntry>();
	for (const record of records) {
		let name = record.name;
		let nameByteLength = record.nameByteLength;
		if (/^\/\d+$/.test(name)) {
			if (!longNames) throw new ArchiveError(`Ar archive member '${name}' references a missing long-name table`);
			const resolved = resolveLongName(name, longNames, options.limits);
			name = resolved.name;
			nameByteLength = resolved.byteLength;
		} else {
			name = shortName(name);
		}
		if (isMetadataName(name)) continue;
		assertArchivePathBytes(nameByteLength, "member path", options.limits.maxPathBytes);
		assertArchiveMemberSize(record.size, name, options.limits);
		const path = normalizeArchiveEntryPath(name);
		if (!path) continue;
		const isDirectory = record.mode !== undefined && (record.mode & FILE_TYPE_MASK) === DIRECTORY_TYPE;
		const entry: ArchiveIndexEntry = {
			path,
			isDirectory,
			size: isDirectory ? 0 : record.size,
			...(record.mtimeSeconds !== undefined ? { mtimeMs: record.mtimeSeconds * 1000 } : {}),
			...(record.mode !== undefined ? { mode: record.mode } : {}),

View on GitHub (pinned to 9690622007)

Solutions

  1. Rebuild the archive with ar so the long-name table is emitted correctly.
  2. Check the archive is complete and not concatenated from partial segments.
  3. Extract with a tolerant tool (e.g. `ar x`) to recover members, then repack.
  4. If you produce archives, ensure the '//' member precedes any member with a '/NNN' name.

Example fix

// before
$ ar rcs bad.a file-with-a-very-long-name.txt  // tool failed to emit table
// after: repack with a conforming ar
$ ar rcs good.a file-with-a-very-long-name.txt
Defensive patterns

Strategy: validation

Validate before calling

function referencesLongNames(names: string[]): boolean {
  return names.some(n => /^\/\d+$/.test(n));
}
// scan raw headers first; if any '/NNN' name exists, require a '//' member before parsing

Try / catch

try {
  return await readUnixAr(source);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('missing long-name table')) {
    throw new Error('archive malformed: member names reference an absent // table');
  }
  throw err;
}

Prevention

When it happens

Trigger: Parsing an ar archive containing a header whose raw name matches /^\/\d+$/ while the '//'-named table member is absent, out of order (after the referring member), or was consumed under different limits.

Common situations: Archives produced by tools that emit long names but omit or misorder the '//' table; concatenated archives where the table lives in the first segment; corruption that dropped the table member.

Related errors


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