can1357/oh-my-pi · error · ArchiveError

Invalid old-GNU ${field}

Error message

Invalid old-GNU ${field}

What it means

Thrown by normalizeOldGnuName when an old-GNU rename record's path is absolute (starts with '/') after backslash-to-slash conversion. The library rejects absolute paths in old-GNU 'N' metadata to prevent archive members escaping the archive root.

Source

Thrown at packages/utils/src/ar/tar.ts:254

}

function paxDeclaresSparse(
	globalPax: ReadonlyMap<string, string>,
	localPax: ReadonlyMap<string, string> | undefined,
): boolean {
	return paxAttribute(globalPax, localPax, PAX_SPARSE_MARKER) === "1";
}

function indexOfAscii(bytes: Uint8Array, value: string, start: number): number {
	for (let offset = start; offset <= bytes.byteLength - value.length; offset++) {
		if (bytesMatchAscii(bytes, offset, value)) return offset;
	}
	return -1;
}

function normalizeOldGnuName(value: string, field: string, limits: ArchiveLimits): string {
	const portable = value.replace(/\\/g, "/");
	if (path.posix.isAbsolute(portable)) throw new ArchiveError(`Invalid old-GNU ${field}`);
	const normalized = normalizeArchiveEntryPath(portable);
	if (!normalized) throw new ArchiveError(`Invalid old-GNU ${field}`);
	assertArchivePathString(normalized, field, limits.maxPathBytes);
	return normalized;
}

function renameOldGnuEntries(
	entries: Map<string, ArchiveIndexEntry>,
	pendingLinks: Map<ArchiveIndexEntry, PendingTarLink>,
	fromPath: string,
	toPath: string,
	limits: ArchiveLimits,
): void {
	const moved = [...entries.entries()].filter(
		([entryPath]) => entryPath === fromPath || entryPath.startsWith(`${fromPath}/`),
	);
	if (moved.length === 0) return;
	for (const [entryPath] of moved) entries.delete(entryPath);

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the archive with `tar tvf` to find the offending old-GNU record and re-pack the archive with a modern tar implementation.
  2. Strip or rewrite the typeflag-'N' records from the archive if the rename metadata is unnecessary.
  3. Treat the archive as untrusted/corrupt and reject it if it comes from an unknown source.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-scan for old-GNU 'N' records with absolute paths before indexing
function hasAbsoluteOldGnuRename(bytes: Uint8Array): boolean {
  // crude scan: block typeflag at offset 156 === 'N' plus 'Rename /' pattern
  for (let off = 0; off + 512 <= bytes.byteLength; ) {
    if (bytes[off + 156] === 0x4e /* N */) return true; // inspect record contents
    const size = /* parse octal size at 124 */ 0;
    off += 512 + Math.ceil(size / 512) * 512;
  }
  return false;
}

Try / catch

try {
  await readTar(bytes, opts);
} catch (e) {
  if (e instanceof ArchiveError && e.message.startsWith("Invalid old-GNU")) {
    throw new Error("Archive contains unsafe old-GNU rename paths; refusing to index");
  }
  throw e;
}

Prevention

When it happens

Trigger: Reading a tar with an old-GNU name record (typeflag 'N') containing 'Rename <abs-path> to ...' where the source path is absolute; the source-path normalization (normalizeOldGnuName(source, "source path")) throws this first.

Common situations: Archives written by very old or non-standard GNU tar variants with odd rename metadata; hand-edited or malicious archives attempting path escape.

Related errors


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