shadcn-ui/ui · error · ConfigParseError

INVALID_CONFIG

INVALID_CONFIG

Error message

Invalid provided config configuration in ${cwd}.

What it means

ConfigParseError (code INVALID_CONFIG) thrown by addRegistryItems when the passed `config` option fails configSchema validation AND already contains a `resolvedPaths` key. The presence of resolvedPaths signals the caller intended to pass a full project config, so a parse failure is treated as a hard error rather than silently falling back. The message includes the resolved cwd and the Zod error details enumerate every invalid field.

Solutions

  1. Read the Zod error details in the message — each line shows `<path>: <message>` pinpointing the offending field.
  2. Either omit `resolvedPaths` from the passed config (so shadcn treats it as a partial config and applies defaults), or pass a fully-valid Config.
  3. If embedding, build Config via the same get-config pipeline shadcn uses internally rather than hand-constructing it.
  4. Upgrade the host to match the shadcn version whose schema you target.

Example fix

// before — partial config that declares resolvedPaths but is invalid
addRegistryItems(['button'], {
  config: { resolvedPaths: { cwd: '/proj' }, aliases: { ui: 123 } }
})

// after — either drop resolvedPaths (partial), or pass a valid full config
addRegistryItems(['button'], {
  config: { aliases: { ui: '@/components/ui' } }
})
Defensive patterns

Strategy: validation

Validate before calling

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

function assertConfigOrPartial(input?: Partial<Config>) {
  if (!input) return
  const parsed = configSchema.safeParse(input)
  if (!parsed.success && 'resolvedPaths' in input) {
    const issues = parsed.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join('; ')
    throw new Error(`Invalid config: ${issues}`)
  }
}

assertConfigOrPartial(options.config)

Type guard

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

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

Try / catch

import { ConfigParseError } from '@/src/registry/errors'

try {
  await addRegistryItems(items, { config })
} catch (e) {
  if (e instanceof ConfigParseError) {
    logger.error(`Config invalid: ${e.message}\nSuggestion: ${e.suggestion}`)
    // fall back to omitting resolvedPaths, or re-resolve via get-config
  } else throw e
}

Prevention

When it happens

Trigger: Calling addRegistryItems({ config }) with a hand-built object that includes resolvedPaths but has invalid structure (wrong types, missing required fields, unknown aliases); a programmatically-constructed Config that drifted from the schema after a shadcn upgrade.

Common situations: Embedding shadcn as a library and passing a Config literal that does not match the current schema; version skew between the host app's expected Config shape and shadcn's; typos in alias keys.

Related errors


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

Appendix: source

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

    path?: string
  } = {}
): Promise<void> {
  if (items.length === 0) {
    return
  }

  const {
    config: inputConfig,
    cwd: inputCwd,
    ...addComponentsOptions
  } = options
  const parsedConfig = configSchema.safeParse(inputConfig)
  if (!parsedConfig.success && inputConfig && "resolvedPaths" in inputConfig) {
    const configCwd =
      typeof inputConfig.resolvedPaths?.cwd === "string"
        ? inputConfig.resolvedPaths.cwd
        : undefined
    throw new ConfigParseError(
      path.resolve(inputCwd ?? configCwd ?? process.cwd()),
      parsedConfig.error,
      "config"
    )
  }

  const configCwd = parsedConfig.success
    ? parsedConfig.data.resolvedPaths.cwd
    : undefined
  const cwd = path.resolve(inputCwd ?? configCwd ?? process.cwd())
  if (
    inputCwd !== undefined &&
    configCwd !== undefined &&
    cwd !== path.resolve(configCwd)
  ) {
    throw new Error("The provided cwd must match config.resolvedPaths.cwd.")
  }

View on GitHub (pinned to efac598707)