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
- Rename the var() reference target to kebab-case: var(--my-var-name) instead of var(--myVarName).
- If the reference target is defined elsewhere, update both the definition and all references to use the kebab-case name consistently.
- 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
- Ensure all var() references use kebab-case custom property names matching the declaration convention.
- When renaming a property, update all its var() references simultaneously.
- Run the theme contract validator in CI to catch invalid references.
- Use find-and-replace with care when renaming tokens to keep declarations and references in sync.
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
- [theme-contract] ${sourceName} declares invalid custom prope
- [theme-contract] renderer theme must use the shared generate
- [theme-contract] renderer stylesheet ${fileName} cannot use
- [theme-contract] unsupported @import syntax: ${importValue}
- [theme-contract] ${label} imports must be exactly: ${expecte
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/20e3e1c7ea93a78c.
Report an issue: GitHub.