ReactiveX/rxjs · error · Error

Output path already exists; enable overwrite explicitly: ${o

Error message

Output path already exists; enable overwrite explicitly: ${outputPath}

What it means

By default the migrator will not overwrite existing output files; this error fires when a planned outputPath already exists as a regular file and the apply options do not include overwrite:true. Re-enabling overwrite is a one-flag opt-in, but the default protects uncommitted work from being clobbered.

Source

Thrown at packages/migrate/src/node.ts:160

  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>'}`);
  }
  const outputPath = resolve(outputRoot, outputName);

View on GitHub (pinned to 54796b38a5)

Solutions

  1. Pass overwrite: true in ApplyMigrationPlanOptions / MigrateFilesOptions if regenerating outputs is intended
  2. Or delete/clean the previous outputs before re-running
  3. Use a fresh outputRoot per run (e.g. a temp dir) to avoid the collision entirely

Example fix

// before
await migrateTestFiles({ ...options, write: true });

// after
await migrateTestFiles({ ...options, write: true, overwrite: true });
Defensive patterns

Strategy: validation

Validate before calling

import { lstat, access } from 'node:fs/promises';
async function outputsMissing(plan: { files: { outputPath: string }[] }): Promise<boolean> {
  for (const f of plan.files) {
    try { await access(f.outputPath); return false; } catch { /* missing is good */ }
  }
  return true;
}
// then: if (await outputsMissing(plan) || wantOverwrite) await applyMigrationPlan(plan, { overwrite: true });

Try / catch

try {
  await migrateTestFiles({ ...options, write: true });
} catch (e) {
  if (e instanceof Error && e.message.includes('enable overwrite explicitly')) {
    await migrateTestFiles({ ...options, write: true, overwrite: true });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling applyMigrationPlan (or migrateTestFiles with write:true) without overwrite when the output file already exists — typically when re-running a migration that already wrote its outputs.

Common situations: Re-running a migration after a partial failure or after inspecting the first run's output; running the same command twice in CI without a clean output directory.

Related errors


AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28). Data as JSON: /api/errors/756eaa98d94f03e4. Report an issue: GitHub.