can1357/oh-my-pi · error · ArchiveError

Unsupported Rock Ridge relocated directory (${susp.relocatio

Error message

Unsupported Rock Ridge relocated directory (${susp.relocation})

What it means

Rock Ridge allows directories to be 'relocated' (deep-directory hacks via CL/RE and PL/NM SUSP entries) so ISO 9660's 8-level nesting limit can be bypassed. This reader does not follow relocated directories: when parseSusp reports a relocation target for a directory record during full traversal, it throws instead of silently misrepresenting the tree.

Source

Thrown at packages/utils/src/ar/iso.ts:521

	while (work.length > 0) {
		const directory = work.pop()!;
		if (directory.depth > MAX_DIRECTORY_DEPTH) {
			throw invalidIso(`directory hierarchy exceeds ${MAX_DIRECTORY_DEPTH} levels`);
		}
		const records = await readDirectoryRecords(source, directory.record, blockSize, budget, limits);
		if (
			directory.depth === 0 &&
			records.length > 0 &&
			records[0]!.identifier.byteLength === 1 &&
			records[0]!.identifier[0] === 0
		) {
			suspSkip = findSuspSkip(records[0]!);
		}
		for (const record of records) {
			if (record.identifier.byteLength === 1 && (record.identifier[0] === 0 || record.identifier[0] === 1)) continue;
			const susp = await parseSusp(record, suspSkip, source, blockSize, budget, limits);
			if (susp.relocation) {
				throw new ArchiveError(`Unsupported Rock Ridge relocated directory (${susp.relocation})`);
			}
			const rawName = susp.name ?? decodeIdentifier(record.identifier, false);
			assertArchivePathBytes(Buffer.byteLength(rawName, "utf-8"), "member name", limits.maxPathBytes);
			const rawPath = directory.parentPath ? `${directory.parentPath}/${rawName}` : rawName;
			const normalizedPath = normalizeArchiveEntryPath(rawPath);
			if (!normalizedPath) continue;
			assertArchivePathBytes(Buffer.byteLength(normalizedPath, "utf-8"), "member path", limits.maxPathBytes);
			if (susp.symlink !== undefined) {
				assertArchivePathBytes(Buffer.byteLength(susp.symlink, "utf-8"), "link target", limits.maxPathBytes);
				const targetPath = path.posix.isAbsolute(susp.symlink)
					? undefined
					: normalizeArchiveLookupPath(path.posix.join(path.posix.dirname(normalizedPath), susp.symlink));
				upsertArchiveEntry(entries, {
					path: normalizedPath,
					isDirectory: false,
					size: 0,
					mtimeMs: record.mtimeMs,
					mode: susp.mode,

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-generate the image without directory relocation: mkisofs/xorriso with -r plus avoiding >8-level nesting (or use -joliet-long/UDF to carry deep paths)
  2. Flatten or restructure the source directory tree to at most 8 levels before creating the ISO
  3. Use an extraction tool that supports RR relocation (e.g. 7z, xorriso -osirrox) to get the files, then re-pack into a supported archive
  4. If you control the image source, disable deep-relocation (mkisofs -D, accepting the ISO limit) or enable UDF

Example fix

// before
$ genisoimage -R -o img.iso deepTree/        # deep relocation dir created -> throws
// after
$ xorriso -as mkisofs -r -D -o img.iso deepTree/  # or restructure tree to <=8 levels
Defensive patterns

Strategy: fallback

Validate before calling

// detect deep relocation marker before reading: look for /RR_MOVED. or hidden relocation dir in listing
const names = await listIsoNames(image);
if (names.some(n => /RR_MOVED/i.test(n))) throw new Error('image uses Rock Ridge deep relocation');

Type guard

null

Try / catch

try {
  entries = await readIsoEntries(image);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('relocated directory')) {
    return extractWith7z(image); // relocation-aware extractor, then re-pack
  }
  throw err;
}

Prevention

When it happens

Trigger: Reading an ISO image (entry/traversal path in iso.ts around line 521) that contains a Rock Ridge relocated directory — i.e. a directory record carrying the CL (child link) SUSP entry marking it as moved to a deeper level — encountered while walking directory records.

Common situations: ISO images with directory nesting deeper than 8 levels produced by mkisofs' -hide-rr-moved-style relocation or modern -rr defaults on very deep trees, notably some Linux distribution trees and backup archives with deep paths.

Related errors


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