remix-run/react-router · error · Error

No project directory provided

Error message

No project directory provided

What it means

Thrown in projectNameStep() when the shell is not interactive (no TTY) and no project directory positional argument was given (ctx.cwd is undefined). In non-interactive mode the CLI cannot prompt for a directory, so it requires one to be supplied on the command line. The check is `if (!ctx.interactive && !ctx.cwd)`.

Source

Thrown at packages/create-react-router/index.ts:220

      color.bold("create-react-router"),
    )} ${color.bold(`v${ctx.reactRouterVersion}`)}`,
  );

  if (!ctx.interactive) {
    log("");
    info("Shell is not interactive.", [
      `Using default options. This is equivalent to running with the `,
      color.reset("--yes"),
      ` flag.`,
    ]);
  }
}

async function projectNameStep(ctx: Context) {
  // valid cwd is required if shell isn't interactive
  if (!ctx.interactive && !ctx.cwd) {
    error("Oh no!", "No project directory provided");
    throw new Error("No project directory provided");
  }

  if (ctx.cwd) {
    await sleep(100);
    info("Directory:", [
      "Using ",
      color.reset(ctx.cwd),
      " as project directory",
    ]);
  }

  if (!ctx.cwd) {
    let { name } = await ctx.prompt({
      name: "name",
      type: "text",
      label: title("dir"),
      message: "Where should we create your new project?",
      initial: "./my-react-router-app",

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Provide the project directory as a positional argument: create-react-router ./my-app.
  2. Add --yes (or -y) and a positional directory for fully non-interactive runs: create-react-router ./my-app --yes.
  3. If you expected a TTY, run the command in an interactive terminal (not via ssh -T or piped stdin).
  4. In CI/Docker, allocate a pseudo-TTY (docker run -it) only if you want prompts; otherwise supply args.

Example fix

// before -- fails in CI
npx create-react-router
// after -- explicit project directory
npx create-react-router ./my-app --yes
Defensive patterns

Strategy: validation

Validate before calling

// Detect non-interactive shell before invoking the CLI
import { statSync } from 'node:fs';
function isInteractiveStdin(): boolean {
  try { return statSync(0).isCharacterDevice(); } catch { return false; }
}
// In your wrapper:
const projectDir = process.argv[2];
if (!isInteractiveStdin() && !projectDir) {
  throw new Error('Pass a project directory: create-react-router <dir>');
}

Prevention

When it happens

Trigger: Running create-react-router with no positional arg in CI, a Dockerfile, a shell script without a TTY, or any piped/non-TTY stdin. Also when stdin/stdout are redirected so isInteractive() returns false.

Common situations: CI script that runs npx create-react-router expecting to prompt; Docker RUN without a TTY; piping yes into the command; running under a process supervisor that doesn't allocate a TTY.

Related errors


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/8c9cd1c795e0f96f. Report an issue: GitHub.