{"record":{"id":"8982f8f773ffbdd4","repo":"shadcn-ui/ui","slug":"base-color-config-basecolor-or-theme-confi","errorCode":null,"errorMessage":"Base color \"${config.baseColor}\" or theme \"${config.theme}\" not found","messagePattern":"Base color \"(.+?)\" or theme \"(.+?)\" not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/v4/registry/config.ts","lineNumber":703,"sourceCode":"    return {\n      success: false as const,\n      error: `Invalid only value. Use one or more of: ${REGISTRY_BASE_PARTS.join(\", \")}`,\n    }\n  }\n\n  return {\n    success: true as const,\n    parts: Array.from(new Set(rawParts.map((part) => aliases[part]))),\n  }\n}\n\n// Builds a registry:theme item from a design system config.\nexport function buildRegistryTheme(config: DesignSystemConfig) {\n  const baseColor = getBaseColor(config.baseColor)\n  const theme = getTheme(config.theme)\n\n  if (!baseColor || !theme) {\n    throw new Error(\n      `Base color \"${config.baseColor}\" or theme \"${config.theme}\" not found`\n    )\n  }\n\n  // Merge base color and theme CSS vars.\n  const lightVars: Record<string, string> = {\n    ...(baseColor.cssVars?.light as Record<string, string>),\n    ...(theme.cssVars?.light as Record<string, string>),\n  }\n  const darkVars: Record<string, string> = {\n    ...(baseColor.cssVars?.dark as Record<string, string>),\n    ...(theme.cssVars?.dark as Record<string, string>),\n  }\n  const themeVars: Record<string, string> = {}\n\n  // Apply chart color override.\n  const chartTheme = getTheme(config.chartColor)\n  if (chartTheme) {","sourceCodeStart":685,"sourceCodeEnd":721,"githubUrl":"https://github.com/shadcn-ui/ui/blob/efac5987074af84ece57c367c6dd83387b967022/apps/v4/registry/config.ts#L685-L721","documentation":"buildRegistryTheme() in registry/config.ts is the canonical registry:theme builder. It resolves config.baseColor via getBaseColor and config.theme via getTheme and throws if either misses. Unlike merge-theme.ts buildTheme (create-time UI), this builds the registry item used by preset resolution and the CLI.","triggerScenarios":"A DesignSystemConfig whose baseColor or theme is not present in BASE_COLORS/THEMES; constructing a config from unvalidated external input; a registry rename that config producers did not follow.","commonSituations":"Server-side preset resolution; CI/tests feeding synthetic configs; presets persisted with now-renamed theme or base-color ids.","solutions":["Validate config.baseColor and config.theme against getBaseColor/getTheme before calling buildRegistryTheme.","When loading stored presets, migrate old ids to current names.","Normalize casing; registry names are lowercase."],"exampleFix":"// before\nbuildRegistryTheme({ ...config, theme: \"NORD\" }) // not registered / wrong case\n\n// after\nbuildRegistryTheme({ ...config, theme: \"nord\" })","handlingStrategy":"validation","validationCode":"import { getBaseColor, getTheme } from \"@/registry/config\"\nif (!getBaseColor(config.baseColor) || !getTheme(config.theme)) {\n  // reject or normalize the preset before building\n}","typeGuard":"import { BASE_COLORS, THEMES } from \"@/registry/config\"\nconst isRegisteredBaseColor = (n: string) => BASE_COLORS.some((c) => c.name === n)\nconst isRegisteredTheme = (n: string) => THEMES.some((t) => t.name === n)","tryCatchPattern":"try {\n  buildRegistryTheme(config)\n} catch (e) {\n  // map to a 400 \"invalid preset\" for the caller\n}","preventionTips":["Generate presets only from current registry names.","Run a migration on preset load to keep ids current."],"tags":["theme","registry","configuration","validation"],"backgroundTag":null,"analyzedSha":"efac5987074af84ece57c367c6dd83387b967022","analyzedAt":"2026-08-12T05:00:50.218Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}