remix-run/remix · warning · UsageError

Target directory is not empty: ${targetDir}. Re-run with --f

Error message

Target directory is not empty: ${targetDir}. Re-run with --force to continue.

What it means

The target directory exists and already contains entries, and --force was not passed, so bootstrap aborts to avoid overwriting existing content. Re-running with --force explicitly opts into writing into the non-empty directory.

Source

Thrown at packages/cli/src/lib/bootstrap-project.ts:174

  }
  packageJson.engines = {
    ...packageJson.engines,
    node: `>=${MINIMUM_SUPPORTED_NODE_VERSION}`,
  }

  await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8')
}

async function ensureTargetDirectory(targetDir: string, force: boolean): Promise<void> {
  try {
    let stats = await fs.stat(targetDir)
    if (!stats.isDirectory()) {
      throw targetPathNotDirectory(targetDir)
    }

    let entries = await fs.readdir(targetDir)
    if (entries.length > 0 && !force) {
      throw targetDirectoryNotEmpty(targetDir)
    }
  } catch (error) {
    let nodeError = error as NodeJS.ErrnoException
    if (nodeError.code !== 'ENOENT') {
      throw error
    }
  }

  await fs.mkdir(targetDir, { recursive: true })
}

async function copyTemplateDirectory({
  sourceDir,
  targetDir,
  templateValues,
}: {
  sourceDir: string
  targetDir: string

View on GitHub (pinned to 9696913134)

Solutions

  1. Re-run with --force to scaffold into the existing directory
  2. Scaffold into a fresh empty directory instead
  3. Clean the target directory (move or delete existing files) first

Example fix

# before
$ remix new .

# after
$ remix new . --force
Defensive patterns

Strategy: validation

Validate before calling

import { readdirSync, existsSync, statSync } from 'node:fs'

function targetIsEmpty(dir: string): boolean {
  if (!existsSync(dir)) return true
  if (!statSync(dir).isDirectory()) return false
  return readdirSync(dir).length === 0
}

Try / catch

try {
  await bootstrapProject({ ...opts, force: opts.force })
} catch (error) {
  if (/not empty/i.test(error.message) && opts.allowOverwrite) {
    return bootstrapProject({ ...opts, force: true })
  }
  throw error
}

Prevention

When it happens

Trigger: ensureTargetDirectory finds entries.length > 0 in the existing targetDir and the force flag is false; any create/scaffold command pointed at a populated directory without --force.

Common situations: Running remix new . inside a repo that already has files (README, .git); re-running scaffolding after a partial failed attempt; pointing at a shared folder with dotfiles (note: any entry counts, including hidden ones).

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/2d5a4bd6451d0c9a. Report an issue: GitHub.