{"record":{"id":"9e55e2ce5a705ab9","repo":"CherryHQ/cherry-studio","slug":"theme-contract-mode-declaration-name-in","errorCode":null,"errorMessage":"[theme-contract] ${mode} ${declaration.name} in ${declaration.source} references undefined ${reference}","messagePattern":"\\[theme-contract\\] (.+?) (.+?) in (.+?) references undefined (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/scripts/validate-theme-contract.ts","lineNumber":187,"sourceCode":"function assertCompatibilityTokensDeclared(\n  label: string,\n  tokenNames: readonly string[],\n  source: string,\n  sourceName: string\n): void {\n  const declarations = new Set(extractDeclarations(source, sourceName).map((declaration) => declaration.name))\n  const missing = tokenNames.map((token) => `--cs-${token}`).filter((name) => !declarations.has(name))\n\n  if (missing.length > 0) {\n    throw new Error(`[theme-contract] ${label} references missing foundation variables: ${missing.join(', ')}`)\n  }\n}\n\nfunction assertReferencesResolve(mode: string, declarations: Map<string, Declaration>): void {\n  for (const declaration of declarations.values()) {\n    for (const reference of extractReferences(declaration.value, declaration.source)) {\n      if (!declarations.has(reference)) {\n        throw new Error(\n          `[theme-contract] ${mode} ${declaration.name} in ${declaration.source} references undefined ${reference}`\n        )\n      }\n    }\n  }\n}\n\nfunction assertNoCycles(mode: string, declarations: Map<string, Declaration>): void {\n  const visited = new Set<string>()\n  const visiting = new Set<string>()\n  const stack: string[] = []\n\n  const visit = (name: string): void => {\n    if (visited.has(name)) return\n    if (visiting.has(name)) {\n      const cycleStart = stack.indexOf(name)\n      throw new Error(`[theme-contract] ${mode} variable cycle: ${[...stack.slice(cycleStart), name].join(' -> ')}`)\n    }","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/ui/scripts/validate-theme-contract.ts#L169-L205","documentation":"Thrown by assertReferencesResolve when a `var(--x)` reference inside a declaration's value does not match any declared variable in the resolved mode graph (light = :root only; dark = :root merged with .dark overrides). Every var() reference must point at a variable declared in the same mode. The message gives the mode, the referencing variable, its source file, and the unresolved reference.","triggerScenarios":"Typing `var(--cs-primay)` instead of `var(--cs-primary)`; referencing a variable that is only declared inside `.dark` from a `:root` declaration; deleting a foundation variable that other layers still reference; writing `var( --cs-x )` with leading whitespace (the extractor handles this and still flags a genuinely missing target).","commonSituations":"Renaming a token in one file without updating its consumers; splitting a variable between light/dark and forgetting the light declaration; rebasing onto a refactor that renamed primitives.","solutions":["Check the spelling of the unresolved reference in the named source file and fix it to match an existing declaration.","If the name is correct, declare the missing variable in the right layer/mode (foundation --cs-* for foundation refs, etc.), or restore it if it was deleted.","If the reference is obsolete, remove the var() and replace with a concrete value or a valid reference."],"exampleFix":"// before (providers.css)\n--cs-primary: var( --cs-missing-primary);\n// after\n--cs-primary: var(--cs-brand-500);","handlingStrategy":"validation","validationCode":"// Pre-resolve every var() reference against the union of declarations in the mode.\nfunction unresolvedRefs(source: string, known: Set<string>) {\n  const out: string[] = []\n  for (const [, name] of source.matchAll(/var\\(\\s*(--[a-z0-9-]+)/g)) {\n    if (!known.has(name)) out.push(name)\n  }\n  return out\n}","typeGuard":null,"tryCatchPattern":"try {\n  validateThemeContractSources(sources)\n} catch (error) {\n  if (error instanceof Error && /references undefined/.test(error.message)) {\n    console.error(error.message) // names the referencing var, source, and undefined ref\n    process.exitCode = 1\n    return\n  }\n  throw error\n}","preventionTips":["After renaming or deleting a token, grep packages/ui/src/styles for var(<old-name>) and update consumers.","Declare a variable in :root before referencing it from :root; only dark-only values may live solely in .dark.","Run theme:check before commit so the reference resolver flags stragglers."],"tags":["theme-contract","css","build","validation"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}