shadcn-ui/ui · error

We could not find a valid `ui` path in your `components.json

Error message

We could not find a valid `ui` path in your `components.json` file. Please ensure you have a valid `ui` path in your `components.json` file.

What it means

Thrown by migrateIcons when no --path was given AND config.resolvedPaths.ui is falsy. Without a user path the migrator falls back to scanning the configured `ui` directory, so an absent ui path leaves nothing to scan. The message points the user at components.json as the source of truth for that path.

Source

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

        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}`)
    }
  } else {
    if (!config.resolvedPaths.ui) {
      throw new Error(
        "We could not find a valid `ui` path in your `components.json` file. Please ensure you have a valid `ui` path in your `components.json` file."
      )
    }

    basePath = config.resolvedPaths.ui
    files = await fg("**/*.{js,ts,jsx,tsx}", {
      cwd: basePath,
    })
  }

  const registryIcons = await getRegistryIcons()

  if (Object.keys(registryIcons).length === 0) {
    throw new Error("Something went wrong fetching the registry icons.")
  }

  const libraryChoices = Object.entries(MIGRATION_ICON_LIBRARIES).map(
    ([name, iconLibrary]) => ({

View on GitHub (pinned to efac598707)

Solutions

  1. Open components.json and confirm `aliases.ui` is set (e.g. "@/components/ui").
  2. Re-run `npx shadcn@latest init` to regenerate a valid components.json with all aliases.
  3. If calling migrateIcons programmatically, ensure the Config passed in has resolvedPaths.ui populated by get-config before invocation.
  4. Alternatively, always pass `--path` to bypass the ui-path fallback entirely.

Example fix

// before — components.json missing aliases.ui
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "aliases": { "components": "@/components" }
}

// after
{
  "$schema": "https://ui.shadcn.com/schema/json",
  "style": "new-york",
  "rsc": true,
  "aliases": { "components": "@/components", "ui": "@/components/ui" }
}
Defensive patterns

Strategy: validation

Validate before calling

function assertUiPath(config: Config) {
  if (!config.resolvedPaths.ui) {
    throw new Error(
      'components.json is missing aliases.ui. Run `npx shadcn@latest init` or pass --path.'
    )
  }
}

// before calling migrateIcons without a path:
assertUiPath(config)

Type guard

function hasUiPath(c: Partial<Config>): c is Config & { resolvedPaths: { ui: string } } {
  return Boolean(c.resolvedPaths && typeof c.resolvedPaths.ui === 'string' && c.resolvedPaths.ui.length > 0)
}

Try / catch

try {
  await migrateIcons(config)
} catch (e) {
  if (e instanceof Error && e.message.includes('valid `ui` path')) {
    // fall back to an explicit path or run init
    await migrateIcons(config, { path: './src/components/ui' })
  } else throw e
}

Prevention

When it happens

Trigger: Invoking `shadcn migrate icons` (no --path) on a project whose components.json has no `aliases.ui` or where the alias resolves to an empty/undefined string. Also occurs when a custom partial Config object is passed programmatically without a resolved `ui` path.

Common situations: components.json was hand-edited and the `aliases.ui` field was deleted; the project uses a non-standard layout and `init` was never run; programmatic callers construct a Config literal and forget resolvedPaths.ui.

Related errors


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