can1357/oh-my-pi · error · ArchiveError

Archive file path is required

Error message

Archive file path is required

What it means

`readFile` requires a non-empty subPath; `normalizeArchiveLookupPath(subPath)` produced an empty/undefined result, so the method throws ArchiveError('Archive file path is required') before doing any lookup. This protects against silently treating an empty path as a root-like lookup (packages/utils/src/ar/reader.ts:130).

Source

Thrown at packages/utils/src/ar/reader.ts:130

				name: nextSegment,
				path: childPath,
				isDirectory,
				size: isDirectory ? 0 : (childEntry?.size ?? entry.size),
				mtimeMs: childEntry?.mtimeMs ?? entry.mtimeMs,
				mode: childEntry?.mode ?? entry.mode,
			});
		}

		return [...children.values()].sort((left, right) =>
			left.name.toLowerCase().localeCompare(right.name.toLowerCase()),
		);
	}

	/** Extract one file member's bytes, following symlink aliases. */
	async readFile(subPath: string): Promise<ExtractedArchiveFile> {
		const normalizedPath = normalizeArchiveLookupPath(subPath);
		if (!normalizedPath) {
			throw new ArchiveError("Archive file path is required");
		}

		const resolvedPath = resolveArchiveLinkPath(this.#entries, normalizedPath, this.limits.maxLinkDepth);
		if (resolvedPath === "") {
			throw new ArchiveError(`Archive path '${normalizedPath}' is a directory`);
		}
		const entry = this.#entries.get(resolvedPath);
		if (!entry) {
			throw new ArchiveError(`Archive file '${normalizedPath}' not found`);
		}
		if (entry.isDirectory) {
			throw new ArchiveError(`Archive path '${normalizedPath}' is a directory`);
		}
		if (!entry.storage) {
			throw new ArchiveError(`Archive file '${normalizedPath}' has no readable storage`);
		}
		assertArchiveMemberSize(entry.size, normalizedPath, this.limits);

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass the concrete file path stored in the archive, e.g. readFile('docs/report.pdf').
  2. Validate the path is a non-empty string before calling: `if (!subPath) throw ...`.
  3. If you meant to list the archive root, use listDirectory() (with no argument) instead of readFile('').
  4. Trace where the empty value comes from (unset config/CLI arg) and add an upstream default or required-arg check.

Example fix

// before
const path = process.env.REPORT_ENTRY ?? ''; 
const file = await reader.readFile(path); // throws when unset

// after
const path = process.env.REPORT_ENTRY;
if (!path) throw new Error('REPORT_ENTRY must name a file inside the archive');
const file = await reader.readFile(path);
Defensive patterns

Strategy: validation

Validate before calling

// Require a concrete file path before calling readFile
function requireFilePath(p: string | undefined): string {
  if (typeof p !== 'string' || p.trim() === '' || p === '.' || p === '/') {
    throw new Error('A file path inside the archive is required');
  }
  return p;
}
await reader.readFile(requireFilePath(configEntryPath));

Type guard

function isNonEmptyPath(p: unknown): p is string {
  return typeof p === 'string' && p.trim().length > 0;
}

Try / catch

try {
  return await reader.readFile(p);
} catch (err) {
  if (err instanceof ArchiveError && err.message === 'Archive file path is required') {
    throw new Error('No archive entry configured — set the file path (use listDirectory() for browsing)');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling `reader.readFile('')`, `readFile(undefined as any)` where an optional path was intended for listDirectory, or a path that normalizes to empty (e.g. '.' or '/' depending on normalization).

Common situations: Config value or CLI flag left empty; template-built path where the variable was unset; copy-paste of listDirectory(undefined) usage into readFile; paths consisting only of separators/dots that normalize away.

Related errors


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