ReactiveX/rxjs · error · Error

${label} is not a directory: ${path}

Error message

${label} is not a directory: ${path}

What it means

Thrown by canonicalDirectory when the given source root exists (realpath resolved) but is not a directory — typically a regular file. The migrate CLI requires real directories for source/output roots before planning a migration.

Source

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

  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;
}

async function canonicalFutureDirectory(path: string, label: string): Promise<string> {
  const resolved = await canonicalFuturePath(path);
  try {
    const pathStats = await stat(path);
    if (!pathStats.isDirectory()) throw new Error(`${label} is not a directory: ${path}`);
  } catch (error: unknown) {
    if (!isMissingPathError(error)) throw error;
  }
  return resolved;
}

/**
 * Resolves every existing prefix through realpath and appends only missing
 * path segments. This detects an existing symlink that redirects a future
 * output outside its declared root without creating any directory first.

View on GitHub (pinned to 54796b38a5)

Solutions

  1. Pass a directory path (e.g. 'src' rather than 'src/index.ts') to the source-root option
  2. Verify with ls/stat that the path is a directory
  3. Fix typos in the configured path

Example fix

// before
await canonicalSourceRoot('src/index.ts');
// after
await canonicalSourceRoot('src');
Defensive patterns

Strategy: validation

Validate before calling

import { stat } from 'node:fs/promises';
if (!(await stat(srcRoot)).isDirectory()) throw new TypeError(`srcRoot must be a directory: ${srcRoot}`);

Type guard

const isDirectory = async (p: string) => (await stat(p)).isDirectory();

Prevention

When it happens

Trigger: Calling canonicalSourceRoot with a path that exists but is a file, e.g. --src src/index.ts instead of a directory.

Common situations: Pointing --src or an input option at a single file, a typo'd path that matches a file, or a broken symlink resolution landing on a file.

Related errors


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