shadcn-ui/ui · error

A full project config is required to resolve target aliases.

Error message

A full project config is required to resolve target aliases.

What it means

Plain Error thrown when the passed config did not fully parse (parsedConfig.success is false) AND hasResolvedTargetAliases returns false for the resolved tree. hasResolvedTargetAliases checks that every file in the tree whose `target` maps to a known alias key has that alias present in config.resolvedPaths. With a partial config, target aliases like `ui`, `lib`, etc. cannot be resolved, so installation would write to unknown locations.

Source

Thrown at packages/shadcn/src/registry/add.ts:86

  )
  const env = await loadEnvFiles(cwd, {
    processEnv: { ...process.env },
  })

  return withRegistryContext(
    async () => {
      const resolvedTree = await resolveRegistryTree(items, config, {
        useCache: true,
        requireUniversal: !parsedConfig.success,
      })
      if (!resolvedTree) {
        throw new Error("Failed to fetch components from registry.")
      }
      if (
        !parsedConfig.success &&
        !hasResolvedTargetAliases(resolvedTree, config)
      ) {
        throw new Error(
          "A full project config is required to resolve target aliases."
        )
      }

      await addComponents(items, config, {
        ...addComponentsOptions,
        interactive: false,
        overwriteCssVars:
          options.overwriteCssVars ??
          (parsedConfig.success ? undefined : false),
        resolvedTree,
      })
    },
    { env }
  )
}

function hasResolvedTargetAliases(

View on GitHub (pinned to efac598707)

Solutions

  1. Pass a full project Config resolved via get-config (so parsedConfig.success is true and the alias check is bypassed).
  2. If passing a partial config, ensure resolvedPaths includes every alias the requested items target (check each item's `target` field).
  3. Run `npx shadcn@latest init` first so components.json has all aliases, then let shadcn resolve the Config itself.
  4. Inspect the resolved tree's files[].target values to see which alias is missing.

Example fix

// before — partial config, items need ui/lib aliases
addRegistryItems(['button', 'use-toast'], {
  config: { style: 'new-york' }
})

// after — pass a full config (resolved via get-config) including aliases
addRegistryItems(['button', 'use-toast'], {
  config: {
    style: 'new-york',
    resolvedPaths: {
      cwd: '/app',
      ui: '/app/src/components/ui',
      lib: '/app/src/lib',
      hooks: '/app/src/hooks'
    }
  }
})
Defensive patterns

Strategy: validation

Validate before calling

import { configSchema } from '@/src/schema'
import { resolveRegistryTree } from '@/src/registry/resolver'
import { getTargetAliasKey } from '@/src/utils/target-aliases'

async function assertTargetAliasesResolvable(items: string[], config: Partial<Config>) {
  const parsed = configSchema.safeParse(config)
  if (parsed.success) return // full config — alias check is bypassed
  const tree = await resolveRegistryTree(items, config as Config, { useCache: false })
  if (!tree) return
  const missing = (tree.files ?? [])
    .map(f => getTargetAliasKey(f.target))
    .filter(k => k && !config.resolvedPaths?.[k])
  if (missing.length) {
    throw new Error(`Partial config missing resolvedPaths for: ${Array.from(new Set(missing)).join(', ')}`)
  }
}

await assertTargetAliasesResolvable(items, options.config ?? {})

Type guard

import { configSchema } from '@/src/schema'

function isFullConfig(c: unknown): c is Config {
  return configSchema.safeParse(c).success
}

Try / catch

try {
  await addRegistryItems(items, { config: partial })
} catch (e) {
  if (e instanceof Error && e.message.includes('full project config')) {
    // re-resolve a full Config via get-config and retry
    const full = await resolveFullConfig(cwd)
    await addRegistryItems(items, { config: full })
  } else throw e
}

Prevention

When it happens

Trigger: Calling addRegistryItems with a partial Config (no resolvedPaths for the required aliases) for items whose registry entries declare `target` fields (e.g. target: 'ui'); passing a config object that omits aliases but requesting items that need them.

Common situations: Embedding shadcn and passing a minimal `{ tailwind: {...} }` config while installing components that target ui/lib/hooks directories; CI scripts that skip running get-config.

Related errors


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