CherryHQ/cherry-studio · error · Error

[theme-contract] ${sourceName} references invalid custom pro

Error message

[theme-contract] ${sourceName} references invalid custom property ${name}

What it means

Thrown by the theme contract validator when a CSS var() reference points to a custom property whose name does not match ^--[a-z0-9-]+$. The extractReferences function scans declaration values for var(--name) patterns and validates each referenced name against the same naming pattern used for declarations. This ensures both definitions and references follow the kebab-case convention.

Source

Thrown at packages/ui/scripts/validate-theme-contract.ts:87

  })
}

function extractModeDeclarations(source: string, sourceName: string, selector: ':root' | '.dark'): Declaration[] {
  const declarations: Declaration[] = []
  const blockPattern = new RegExp(`${escapeRegExp(selector)}\\s*\\{([\\s\\S]*?)\\}`, 'g')

  for (const match of stripComments(source).matchAll(blockPattern)) {
    declarations.push(...extractDeclarations(match[1], sourceName))
  }

  return declarations
}

function extractReferences(value: string, sourceName: string): string[] {
  return [...value.matchAll(/var\(\s*(--[^\s,)]+)/g)].map((match) => {
    const name = match[1]
    if (!CUSTOM_PROPERTY_NAME_PATTERN.test(name)) {
      throw new Error(`[theme-contract] ${sourceName} references invalid custom property ${name}`)
    }
    return name
  })
}

function extractImports(source: string): string[] {
  return [...stripComments(source).matchAll(/@import\s+([^;]+);/g)].map((match) => {
    const importValue = match[1].trim()
    const stringMatch = importValue.match(/^(['"])([^'"]+)\1$/)
    if (stringMatch) return stringMatch[2]

    const urlMatch = importValue.match(/^url\(\s*(?:(['"])([^'"]+)\1|([^'")\s][^)]*?))\s*\)$/)
    if (urlMatch) return (urlMatch[2] ?? urlMatch[3]).trim()

    throw new Error(`[theme-contract] unsupported @import syntax: ${importValue}`)
  })
}

View on GitHub (pinned to 726446b54c)

Solutions

  1. Rename the var() reference target to kebab-case: var(--my-var-name) instead of var(--myVarName).
  2. If the reference target is defined elsewhere, update both the definition and all references to use the kebab-case name consistently.
  3. Run the validator to confirm: npx tsx packages/ui/scripts/validate-theme-contract.ts.

Example fix

/* before */
--accent: var(--brand_Color);
--text: var(--primaryText);

/* after — kebab-case references */
--accent: var(--brand-color);
--text: var(--primary-text);
Defensive patterns

Strategy: validation

Validate before calling

// Validate var() references in CSS before committing
import { readFileSync } from 'node:fs'

const VALID_NAME = /^--[a-z0-9-]+$/

function checkReferences(cssPath: string): void {
  const source = readFileSync(cssPath, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '')
  const refs = [...source.matchAll(/var\(\s*(--[^\s,)]+)/g)]
  for (const match of refs) {
    if (!VALID_NAME.test(match[1])) {
      throw new Error(`${cssPath}: invalid reference ${match[1]} — use kebab-case`)
    }
  }
}

Prevention

When it happens

Trigger: A CSS declaration's value contains a var() reference like var(--my_Var) or var(--MyColor) where the referenced name has uppercase, underscores, or invalid characters. The validator catches this when parsing references within any declaration value processed by extractReferences.

Common situations: A developer writes var(--camelCaseName) or var(--snake_case_name) in a CSS value. A typo in a var() reference. Copy-pasting a reference from external CSS that uses non-conforming names. Renaming a property but forgetting to update its references.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/20e3e1c7ea93a78c. Report an issue: GitHub.