{"record":{"id":"aa9c8d2966f0c73b","repo":"CherryHQ/cherry-studio","slug":"theme-contract-shadcn-css-declares-unregistered","errorCode":null,"errorMessage":"[theme-contract] shadcn.css declares unregistered Shadcn variable ${declaration.name}","messagePattern":"\\[theme-contract\\] shadcn\\.css declares unregistered Shadcn variable (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/scripts/validate-theme-contract.ts","lineNumber":355,"sourceCode":"  }\n  assertCompatibilityTokensDeclared(\n    'compatibility semantic colors',\n    COMPATIBILITY_SEMANTIC_COLOR_TOKENS,\n    sources.providerColors,\n    'tokens/colors/providers.css'\n  )\n  assertCompatibilityTokensDeclared(\n    'compatibility status colors',\n    COMPATIBILITY_STATUS_COLOR_TOKENS,\n    sources.statusLegacyColors,\n    'tokens/colors/status-legacy.css'\n  )\n\n  const shadcnRootDeclarations = buildDeclarationMap([['shadcn.css', sources.shadcn]], ':root')\n  assertRequiredDeclarations('Shadcn contract in shadcn.css', shadcnRootDeclarations, SHADCN_VARIABLE_TOKENS, '--')\n  for (const declaration of extractDeclarations(sources.shadcn, 'shadcn.css')) {\n    if (!shadcnVariableNames.has(declaration.name)) {\n      throw new Error(`[theme-contract] shadcn.css declares unregistered Shadcn variable ${declaration.name}`)\n    }\n  }\n\n  const productRootDeclarations = buildDeclarationMap([['product.css', sources.product]], ':root')\n  assertRequiredDeclarations(\n    'product contract in product.css',\n    productRootDeclarations,\n    CHERRY_PRODUCT_VARIABLE_TOKENS,\n    '--'\n  )\n\n  assertSurfacePairs('Shadcn contract', SHADCN_SURFACE_PAIRS, shadcnVariables)\n  assertSurfacePairs('product contract', CHERRY_PRODUCT_SURFACE_PAIRS, productVariables)\n\n  assertExactImports('tokens.css', sources.tokensEntry, ['./tokens/index.css'])\n  assertExactImports('tokens/index.css', sources.tokensIndex, [\n    './colors/primitive.css',\n    './colors/status-legacy.css',","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/ui/scripts/validate-theme-contract.ts#L337-L373","documentation":"Thrown by validateThemeContractSources when shadcn.css declares a --<name> variable that is not in the SHADCN_VARIABLE_TOKENS registry. The Shadcn contract is a closed set; only registered official variables may be declared there. This catches product roles (e.g. --success) or invented Shadcn roles leaking into shadcn.css.","triggerScenarios":"Adding `:root { --success: hotpink; }` to shadcn.css (success is a product variable); inventing a new official role `--new-role` without registering it; pasting a product declaration into shadcn.css.","commonSituations":"Adding a Shadcn component's variable to the wrong file; extending the Shadcn surface and forgetting the registry.","solutions":["If it is a genuine new official Shadcn variable, register the unprefixed name in SHADCN_VARIABLE_TOKENS in scripts/theme-contract.ts, declare it in shadcn.css :root, and document it in variable-catalog.md.","If it is a product role (e.g. --success), move the declaration to product.css and ensure it is in CHERRY_PRODUCT_VARIABLE_TOKENS.","Re-run `pnpm --filter @cherrystudio/ui theme:check`."],"exampleFix":"// before (shadcn.css)\n:root { --success: hotpink; }\n// after — move to product.css (success is a product token)\n// product.css\n:root { --success: var(--cs-green-600); }","handlingStrategy":"validation","validationCode":"// Every variable declared in shadcn.css must be a registered Shadcn variable.\nconst allowed = new Set(SHADCN_VARIABLE_TOKENS.map((t) => `--${t}`))\nconst offenders = [...sources.shadcn.matchAll(/(?:^|[;{])\\s*(--[a-z0-9-]+)\\s*:/g)].map((m) => m[1]).filter((n) => !allowed.has(n))\nif (offenders.length) throw new Error(`shadcn.css declares unregistered vars: ${offenders.join(', ')}`)","typeGuard":null,"tryCatchPattern":"try {\n  validateThemeContractSources(sources)\n} catch (error) {\n  if (error instanceof Error && /shadcn\\.css declares unregistered Shadcn variable/.test(error.message)) {\n    console.error(error.message)\n    process.exitCode = 1\n    return\n  }\n  throw error\n}","preventionTips":["Only official SHADCN_VARIABLE_TOKENS may be declared in shadcn.css.","Product roles (--success, --link, ...) belong in product.css, not shadcn.css.","When extending the Shadcn surface, update the registry, the CSS, and the catalog together."],"tags":["theme-contract","css","build","validation","registry"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}