ReactiveX/rxjs · error · Error
Output name must be a non-empty relative path: ${outputName
Error message
Output name must be a non-empty relative path: ${outputName || '<empty>'} What it means
safeOutputPath builds each output path by resolving a relative name against outputRoot, and rejects names that are empty, '.', or absolute. Absolute or degenerate names would either escape the outputRoot contract or fail to identify a file, so they are treated as programming errors in the outputName configuration.
Source
Thrown at packages/migrate/src/node.ts:176
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>'}`);
}
const outputPath = resolve(outputRoot, outputName);
if (outputPath === outputRoot) throw new Error(`Output name must identify a file below outputRoot: ${outputName}`);
assertContained(outputRoot, outputPath, `Output path is outside outputRoot: ${outputName}`);
return outputPath;
}
function assertContained(root: string, candidate: string, message: string): void {
const localPath = relative(root, candidate);
if (localPath === '' || (localPath !== '..' && !localPath.startsWith(`..${sep}`) && !isAbsolute(localPath))) return;
throw new Error(message);
}
async function canonicalDirectory(path: string, label: string): Promise<string> {
const canonicalPath = await realpath(path);
const pathStats = await stat(canonicalPath);
if (!pathStats.isDirectory()) throw new Error(`${label} is not a directory: ${path}`);
return canonicalPath;View on GitHub (pinned to 54796b38a5)
Solutions
- Make outputName always return a non-empty relative path with a file extension
- If the callback computes absolute paths, strip the outputRoot prefix first (path.relative(outputRoot, p))
- Guard the callback's fallback branch so it never returns undefined for unmatched files
Example fix
// before
outputName: ({ sourcePath }) => absoluteNames.get(sourcePath),
// after
outputName: ({ sourcePath, sourceRoot }) =>
path.relative(sourceRoot, sourcePath).replaceAll('\\', '/'), Defensive patterns
Strategy: validation
Validate before calling
import { isAbsolute } from 'node:path';
function validOutputName(name: string): boolean {
return Boolean(name) && name !== '.' && !isAbsolute(name);
} Type guard
function isRelativeOutputName(name: unknown): name is string {
return typeof name === 'string' && name.length > 0 && name !== '.' && !isAbsolute(name);
} Prevention
- Unit-test your outputName callback over all input filenames including edge cases
- Return path.relative(...) from name callbacks that internally compute absolute paths
When it happens
Trigger: A custom options.outputName function returning '', '.', or an absolute path like '/tmp/out.spec.ts' (or a value starting with '/' or a Windows drive letter); also triggered when a string outputName is empty.
Common situations: A name-mapping callback that returns undefined/null coerced to string on edge cases, or one that resolves names against the wrong root and returns an absolute path.
Related errors
- Output name must identify a file below outputRoot: ${outputN
- Output path must identify a file below outputRoot: ${outputP
- Output path is not a regular file: ${outputPath}
- Duplicate output path: ${outputLocalName}
- Duplicate output path: ${outputPath}
AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28).
Data as JSON: /api/errors/0a8ce22421a4d7ce.
Report an issue: GitHub.