ReactiveX/rxjs · error · Error
Output path is not a regular file: ${outputPath}
Error message
Output path is not a regular file: ${outputPath} What it means
When a planned output path already exists and is neither a symlink nor a regular file (i.e. it is a directory, FIFO, socket, or device), assertWritableOutput refuses to proceed. Writing file bytes over such an entry is never safe — especially a directory — so the migrator aborts before touching anything.
Source
Thrown at packages/migrate/src/node.ts:159
const canonicalOutputs = new Set<string>();
for (const { sourcePath, outputPath, result } of plan.files) {
if (result.status === 'refused') throw new Error(`Migration result was refused for source: ${sourcePath}`);
const resolvedOutputPath = resolve(outputPath);
if (resolvedOutputPath === outputRoot) throw new Error(`Output path must identify a file below outputRoot: ${outputPath}`);
assertContained(outputRoot, resolvedOutputPath, `Output path is outside outputRoot: ${outputPath}`);
const canonicalOutputPath = await canonicalFuturePath(resolvedOutputPath);
assertContained(canonicalOutputRoot, canonicalOutputPath, `Output path resolves outside outputRoot: ${outputPath}`);
if (canonicalOutputs.has(canonicalOutputPath)) throw new Error(`Duplicate output path: ${outputPath}`);
canonicalOutputs.add(canonicalOutputPath);
await assertWritableOutput(resolvedOutputPath, options.overwrite ?? false);
}
}
async function assertWritableOutput(outputPath: string, overwrite: boolean): Promise<void> {
try {
const outputStats = await lstat(outputPath);
if (outputStats.isSymbolicLink()) throw new Error(`Refusing to overwrite a symbolic link: ${outputPath}`);
if (!outputStats.isFile()) throw new Error(`Output path is not a regular file: ${outputPath}`);
if (!overwrite) throw new Error(`Output path already exists; enable overwrite explicitly: ${outputPath}`);
} catch (error: unknown) {
if (!isMissingPathError(error)) throw error;
}
}
export async function migrateTestFiles(options: MigrateFilesOptions): Promise<readonly MigratedFile[]> {
if (options.write && !options.outputRoot) {
throw new Error('outputRoot is required when write is enabled.');
}
const plan = await planMigrationFiles(options);
return options.write ? applyMigrationPlan(plan, { overwrite: options.overwrite }) : plan.files;
}
function safeOutputPath(outputRoot: string, outputName: string): string {
if (!outputName || outputName === '.' || isAbsolute(outputName)) {
throw new Error(`Output name must be a non-empty relative path: ${outputName || '<empty>'}`);
}View on GitHub (pinned to 54796b38a5)
Solutions
- Remove or rename the directory currently occupying the output path
- Fix outputName so it always produces a file-like name with an extension
- Choose a different outputRoot that does not contain conflicting directory names
Example fix
// before
outputName: ({ sourcePath }) => basename(sourcePath, '.spec.ts'), // collides with dir
// after
outputName: ({ sourcePath }) => basename(sourcePath, '.spec.ts') + '.spec.ts', Defensive patterns
Strategy: validation
Validate before calling
import { lstat } from 'node:fs/promises';
async function allOutputsAreRegularFilesOrMissing(plan: { files: { outputPath: string }[] }): Promise<boolean> {
for (const f of plan.files) {
try { if (!(await lstat(f.outputPath)).isFile()) return false; }
catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }
}
return true;
} Prevention
- Ensure outputName always yields a filename with an extension
- Check the output tree for pre-existing directories with colliding names before running
When it happens
Trigger: Calling applyMigrationPlan when a planned files[].outputPath exists and lstat reports a non-file, non-symlink type; most commonly outputPath names an existing directory.
Common situations: An outputName function that drops the file extension, making outputPath collide with an existing directory of the same name; leftover directories from a previous tool run.
Related errors
- Output path must identify a file below outputRoot: ${outputP
- Refusing to overwrite a symbolic link: ${outputPath}
- Output path already exists; enable overwrite explicitly: ${o
- Output name must be a non-empty relative path: ${outputName
- Output name must identify a file below outputRoot: ${outputN
AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28).
Data as JSON: /api/errors/4a8871a0bfe361e7.
Report an issue: GitHub.