shadcn-ui/ui · error · Error

Unknown base color: ${sourceBaseColor}.

Error message

Unknown base color: ${sourceBaseColor}.

What it means

migrateBaseColor fetches the source palette definition via getRegistryBaseColor(sourceBaseColor), which loads colors/<name>.json from the registry. The source is intentionally NOT validated against BASE_COLORS earlier (legacy colors like slate are allowed), so an unrecognized name surfaces here as "Unknown base color" when the lookup resolves without a usable color. (A hard 404 on the registry instead raises a separate registry fetch error.)

Source

Thrown at packages/shadcn/src/migrations/migrate-base-color.ts:137

      initial: true,
      message: `We will migrate ${highlighter.info(
        relativePath
      )} from ${highlighter.info(sourceBaseColor)} to ${highlighter.info(
        targetBaseColor
      )}. Continue?`,
    })

    if (!confirm) {
      logger.info("Migration cancelled.")
      process.exit(0)
    }
  }

  const sourceColor = await getRegistryBaseColor(sourceBaseColor)
  const targetColor = await getRegistryBaseColor(targetBaseColor)

  if (!sourceColor) {
    throw new Error(`Unknown base color: ${sourceBaseColor}.`)
  }

  if (!targetColor) {
    throw new Error("Something went wrong fetching the base colors.")
  }

  const projectInfo = await getProjectInfo(config.resolvedPaths.cwd)
  const tailwindVersion = projectInfo?.tailwindVersion ?? "v4"

  const sourceVars = getBaseColorCssVars(sourceColor, tailwindVersion)
  const targetVars = getBaseColorCssVars(targetColor, tailwindVersion)

  const migrationSpinner = spinner(`Migrating base color...`)?.start()

  const raw = await fs.readFile(config.resolvedPaths.tailwindCss, "utf-8")
  const { cssVars, skipped } = getBaseColorMigration(
    raw,
    sourceVars,

View on GitHub (pinned to c06da1d0e9)

Solutions

  1. Pass an explicit, existing source: `--from neutral` (or another available name) instead of relying on the config value.
  2. Fix components.json: set tailwind.baseColor to a supported name (neutral, zinc, stone, mauve, olive, mist, taupe) and re-run.
  3. If REGISTRY_URL points at a private mirror, verify it actually serves colors/<name>.json (curl $REGISTRY_URL/colors/neutral.json); otherwise unset the override so the default registry is used.

Example fix

// before — components.json has a stale/custom name
"tailwind": { "baseColor": "slate-dark", ... }
npx shadcn@latest migrate base-color --to neutral
// -> Unknown base color: slate-dark.

// after
"tailwind": { "baseColor": "neutral", ... }
npx shadcn@latest migrate base-color --to zinc
Defensive patterns

Strategy: try-catch

Validate before calling

const AVAILABLE = new Set(['neutral', 'zinc', 'stone', 'mauve', 'olive', 'mist', 'taupe', /* legacy sources your registry still serves, e.g. */ 'slate', 'gray'])

// Validate --from (or the config's baseColor) before running the CLI:
function assertKnownSource(name: string | undefined): void {
  if (!name || !AVAILABLE.has(name)) {
    throw new Error(
      `Unknown source base color "${name}". Fix tailwind.baseColor in components.json or pass --from.`
    )
  }
}

Type guard

function isKnownBaseColor(name: string): boolean {
  const available = ['neutral', 'zinc', 'stone', 'mauve', 'olive', 'mist', 'taupe', 'slate', 'gray']
  return available.includes(name)
}

Try / catch

try {
  await migrateBaseColor(config, { from, to, yes: true })
} catch (error) {
  const message = error instanceof Error ? error.message : String(error)
  if (message.startsWith('Unknown base color:')) {
    // Input problem: fix --from or tailwind.baseColor in components.json, then retry.
    const bad = message.match(/Unknown base color: (\w+)/)?.[1]
    throw new Error(`Fix the base color "${bad}" in components.json or pass --from with a valid name.`)
  }
  throw error // registry/network errors bubble up separately
}

Prevention

When it happens

Trigger: Passing --from with a name the registry does not serve (custom typo, invented name), or having a stale/custom `tailwind.baseColor` in components.json that no colors/<name>.json exists for — especially when REGISTRY_URL points at a private mirror that omits the legacy color files.

Common situations: Old projects carrying legacy palette names in components.json; corporate registries/mirrors that only proxy component items but not colors/*.json; hand-edited configs; a REGISTRY_URL override left set in the environment.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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