shadcn-ui/ui · error

File not found

Error message

File not found: ${options.path}

What it means

During `shadcn migrate icons --path <p>`, when <p> is not a glob and fs.stat resolves to null (ENOENT), the path does not exist on disk. Note the path is resolved against config.resolvedPaths.cwd, NOT the shell's process.cwd().

Solutions

  1. Verify the path exists: `ls <path>` from the project root.
  2. Use an absolute path to avoid cwd confusion.
  3. Drop --path entirely to migrate the configured `ui` directory from components.json.

Example fix

// before
shadcn migrate icons --path ./src/components
// after (absolute, or omit)
shadcn migrate icons --path /abs/path/to/components
// or: shadcn migrate icons   (uses components.json `ui`)
Defensive patterns

Strategy: validation

Validate before calling

import fs from "fs-extra"
import path from "path"

async function assertMigratePathExists(configCwd: string, p: string) {
  // NOTE: resolved against config.resolvedPaths.cwd, not process.cwd().
  if (!p.includes("*")) {
    const stat = await fs.stat(path.resolve(configCwd, p)).catch(() => null)
    if (!stat) throw new Error(`File not found: ${p}`)
  }
}

Type guard

import fs from "fs-extra"
import path from "path"

async function isExistingMigratePath(configCwd: string, p: string): Promise<boolean> {
  if (p.includes("*")) return true
  const stat = await fs.stat(path.resolve(configCwd, p)).catch(() => null)
  return !!stat
}

Prevention

When it happens

Trigger: Passing --path to `shadcn migrate icons` that does not resolve under the project's configured cwd (config.resolvedPaths.cwd).

Common situations: Typo in path, wrong relative path (resolved against config cwd not shell cwd), file moved/deleted between planning and execution, running migrate from a subdirectory.

Related errors


AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12). Data as JSON: /api/errors/a1dd9c359e3f2dc9. Report an issue: GitHub.

Appendix: source

Thrown at packages/shadcn/src/migrations/migrate-icons.ts:85

  let basePath: string

  if (options.path) {
    // User provided a path/glob.
    basePath = config.resolvedPaths.cwd
    const isGlob = options.path.includes("*")

    if (isGlob) {
      files = await fg(options.path, {
        cwd: basePath,
        onlyFiles: true,
        ignore: ["**/node_modules/**"],
      })
    } else {
      const fullPath = path.resolve(basePath, options.path)
      const stat = await fs.stat(fullPath).catch(() => null)

      if (!stat) {
        throw new Error(`File not found: ${options.path}`)
      }

      if (stat.isDirectory()) {
        basePath = fullPath
        files = await fg("**/*.{js,ts,jsx,tsx}", {
          cwd: basePath,
          onlyFiles: true,
          ignore: ["**/node_modules/**"],
        })
      } else if (stat.isFile()) {
        files = [options.path]
      } else {
        throw new Error(`Unsupported path type: ${options.path}`)
      }
    }

    if (files.length === 0) {
      throw new Error(`No files found matching: ${options.path}`)

View on GitHub (pinned to efac598707)