can1357/oh-my-pi · error · ArchiveError
Archive path '${normalizedPath}' is not a directory
Error message
Archive path '${normalizedPath}' is not a directory What it means
`listDirectory` found an entry at the resolved path, but it is a regular file (or other non-directory member), so it throws ArchiveError(`Archive path '${normalizedPath}' is not a directory`). Directory listing only works on entries flagged isDirectory (packages/utils/src/ar/reader.ts:88).
Source
Thrown at packages/utils/src/ar/reader.ts:88
}
/** List one directory's children, sorted case-insensitively by name. */
listDirectory(subPath?: string): ArchiveDirectoryEntry[] {
const normalizedPath = normalizeArchiveLookupPath(subPath);
if (normalizedPath === undefined) {
throw new ArchiveError("Archive path cannot contain '..'");
}
const resolvedPath = normalizedPath
? resolveArchiveLinkPath(this.#entries, normalizedPath, this.limits.maxLinkDepth)
: "";
if (normalizedPath && resolvedPath !== "") {
const entry = this.#entries.get(resolvedPath);
if (!entry) {
throw new ArchiveError(`Archive path '${normalizedPath}' not found`);
}
if (!entry.isDirectory) {
throw new ArchiveError(`Archive path '${normalizedPath}' is not a directory`);
}
}
const sourcePrefix = resolvedPath ? `${resolvedPath}/` : "";
const children = new Map<string, ArchiveDirectoryEntry>();
for (const entry of this.#entries.values()) {
if (resolvedPath) {
if (!entry.path.startsWith(sourcePrefix) || entry.path === resolvedPath) continue;
}
const relativePath = resolvedPath ? entry.path.slice(sourcePrefix.length) : entry.path;
const nextSegment = relativePath.split("/")[0];
if (!nextSegment) continue;
const childPath = normalizedPath ? `${normalizedPath}/${nextSegment}` : nextSegment;
if (children.has(childPath)) continue;
View on GitHub (pinned to 9690622007)
Solutions
- Check `entry.isDirectory` from allEntries() before calling listDirectory; use readFile for file entries instead.
- If you want the parent folder of a file, derive it (strip the last path segment) and list that directory.
- Catch this ArchiveError and dispatch to readFile when the path turns out to be a file.
- For symlink paths, resolve intent first: inspect the entry's target and its isDirectory flag.
Example fix
// before: same handler for any path
const kids = reader.listDirectory(targetPath);
// after: branch on entry type
const entry = reader.allEntries().find(e => e.path === targetPath);
if (entry && !entry.isDirectory) {
const file = await reader.readFile(targetPath);
} else {
const kids = reader.listDirectory(targetPath);
} Defensive patterns
Strategy: type-guard
Validate before calling
// Check entry kind before choosing the API
const entry = reader.allEntries().find(e => e.path === targetPath);
if (entry && !entry.isDirectory) {
await reader.readFile(targetPath); // file path
} else {
reader.listDirectory(targetPath); // directory path
} Type guard
function isFileEntry(
entries: { path: string; isDirectory: boolean }[],
p: string,
): boolean {
const e = entries.find(x => x.path === p);
return e !== undefined && !e.isDirectory;
} Try / catch
try {
return reader.listDirectory(p);
} catch (err) {
if (err instanceof ArchiveError && err.message.endsWith('is not a directory')) {
return { kind: 'file' as const, read: () => reader.readFile(p) };
}
throw err;
} Prevention
- Branch on entry.isDirectory before calling listDirectory vs readFile.
- If the caller wants a file's folder, derive the parent path (strip last segment) and list that.
- Do not assume trailing-slash-less names are files; check the entry map.
- Centralize this dispatch in one helper so callers cannot pick the wrong API.
When it happens
Trigger: Calling `reader.listDirectory('file.txt')` where that path maps to a file entry; passing a symlink that resolves to a file instead of a directory; confusing the file/directory listing APIs (readFile vs listDirectory) with the same path.
Common situations: Code that walks archives generically and calls listDirectory on every entry without checking isDirectory; paths that look like directories because of extensions but are files; API misuse where readFile should have been used.
Related errors
- Archive path '${normalizedPath}' not found
- Archive path '${normalizedPath}' is a directory
- Archive file '${normalizedPath}' not found
- cannot access {}: Not a directory
- invalid template, {}; with --tmpdir, it may not be absolute
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/35c554cc45e6bd4a.
Report an issue: GitHub.