ReactiveX/rxjs · error · Error
An output path ancestor is not a directory: ${existing}
Error message
An output path ancestor is not a directory: ${existing} What it means
Thrown by canonicalFuturePath when an output path has missing trailing components (to be created) but the nearest existing ancestor on disk is not a directory, so the missing children could never be created. It protects output paths like dist/gen/ where 'dist' exists as a file.
Source
Thrown at packages/migrate/src/node.ts:230
*/
async function canonicalFuturePath(path: string): Promise<string> {
const missing: string[] = [];
let existing = path;
let canonicalExisting: string | undefined;
while (canonicalExisting === undefined) {
try {
canonicalExisting = await realpath(existing);
} catch (error: unknown) {
if (!isMissingPathError(error)) throw error;
const parent = dirname(existing);
if (parent === existing) throw error;
missing.push(basename(existing));
existing = parent;
}
}
if (missing.length > 0) {
const existingStats = await stat(canonicalExisting);
if (!existingStats.isDirectory()) throw new Error(`An output path ancestor is not a directory: ${existing}`);
}
return resolve(canonicalExisting, ...missing.reverse());
}
function isMissingPathError(error: unknown): error is NodeJS.ErrnoException {
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
}
View on GitHub (pinned to 54796b38a5)
Solutions
- Remove the file blocking the ancestor directory (rm <file>)
- Use an output path whose existing ancestors are all directories
- Pick a fresh output directory name
Example fix
# before plan --output dist/gen # dist is a file # after rm dist && mkdir -p dist && plan --output dist/gen
Defensive patterns
Strategy: validation
Validate before calling
import { stat } from 'node:fs/promises';
let cur = path.dirname(outPath);
while (true) {
try { if (!(await stat(cur)).isDirectory()) throw new Error(`ancestor not a directory: ${cur}`); break; } catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; cur = path.dirname(cur); if (cur === path.dirname(cur)) break; }
} Prevention
- Run mkdir -p on the output root before migrating
- Avoid output paths that reuse names of existing files
When it happens
Trigger: Calling canonicalOutputPath (or skill-install's canonicalFuturePath) with a path such as 'dist/a/b' where 'dist' exists as a regular file, so walking up finds a non-directory ancestor.
Common situations: Output directories nested under a path occupied by a file from an earlier build, git artifacts, or editor swap files blocking directory creation.
Related errors
- ${message}
- ${label} is not a directory: ${path}
- Project root is not a directory: ${projectRoot}
- Canonical Skill root is not a directory: ${canonicalSkillRoo
- ${message}
AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28).
Data as JSON: /api/errors/f0be2dd51a29442c.
Report an issue: GitHub.