CherryHQ/cherry-studio · error · Error
[theme-contract] ${label} contains duplicate names
Error message
[theme-contract] ${label} contains duplicate names What it means
Thrown by the theme contract validator when a labeled list of token names contains duplicates. The assertUnique function checks that new Set(values).size === values.length for various token arrays (runtime theme inputs, Shadcn variables, product variables, Tailwind product colors, compatibility tokens). A duplicate means the same variable name appears twice in a source-of-truth token list, which would cause ambiguous resolution.
Source
Thrown at packages/ui/scripts/validate-theme-contract.ts:108
})
}
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}`)
})
}
function assertUnique(label: string, values: readonly string[]): void {
if (new Set(values).size !== values.length) {
throw new Error(`[theme-contract] ${label} contains duplicate names`)
}
}
function assertSurfacePairs(
label: string,
pairs: ReadonlyArray<readonly [surface: string, foreground: string]>,
variableNames: Set<string>
): void {
const surfaces = new Set<string>()
for (const [surface, foreground] of pairs) {
if (surface === foreground || surfaces.has(surface)) {
throw new Error(`[theme-contract] ${label} has an invalid or duplicate surface pair for ${surface}`)
}
if (!variableNames.has(surface) || !variableNames.has(foreground)) {
throw new Error(`[theme-contract] ${label} pair ${surface} / ${foreground} is outside its public contract`)
}
surfaces.add(surface)View on GitHub (pinned to 726446b54c)
Solutions
- Inspect the token constant array identified by the label in the error message (e.g., 'Shadcn variables', 'product variables') in packages/ui/scripts/theme-contract.ts.
- Remove the duplicate entry so each name appears exactly once.
- Run the validator to confirm: npx tsx packages/ui/scripts/validate-theme-contract.ts.
Example fix
// before — packages/ui/scripts/theme-contract.ts export const SHADCN_VARIABLE_TOKENS = [ 'background', 'foreground', 'background', // ← duplicate 'card' ] as const // after — remove duplicate export const SHADCN_VARIABLE_TOKENS = [ 'background', 'foreground', 'card' ] as const
Defensive patterns
Strategy: validation
Validate before calling
// Check token arrays for duplicates before committing theme-contract.ts changes
import { SHADCN_VARIABLE_TOKENS, CHERRY_PRODUCT_VARIABLE_TOKENS, RUNTIME_THEME_INPUT_TOKENS } from './theme-contract'
function assertUnique(label: string, values: readonly string[]): void {
if (new Set(values).size !== values.length) {
const dupes = values.filter((v, i) => values.indexOf(v) !== i)
throw new Error(`${label} has duplicates: ${dupes.join(', ')}`)
}
}
assertUnique('Shadcn variables', SHADCN_VARIABLE_TOKENS)
assertUnique('product variables', CHERRY_PRODUCT_VARIABLE_TOKENS)
assertUnique('runtime inputs', RUNTIME_THEME_INPUT_TOKENS) Prevention
- When adding a token to an array in theme-contract.ts, search the array first to confirm it's not already present.
- Run the theme contract validator after any change to token arrays.
- Use alphabetical ordering within token arrays to make duplicates visually obvious.
- Review token arrays during code review specifically for duplicate entries.
When it happens
Trigger: A token constant array in packages/ui/scripts/theme-contract.ts (e.g., SHADCN_VARIABLE_TOKENS, CHERRY_PRODUCT_VARIABLE_TOKENS, RUNTIME_THEME_INPUT_TOKENS, or one of the COMPATIBILITY_*_TOKENS arrays) contains the same string twice. The validator calls assertUnique on each array at the start of validateThemeContractSources.
Common situations: A developer adds a new token to a constant array but it was already present (e.g., adding 'background' when it's already listed). Copy-paste error when extending the token lists. A merge that combined two branches each adding the same token. Refactoring that moved tokens between arrays without removing the original.
Related errors
- [theme-contract] ${label} has an invalid or duplicate surfac
- [theme-contract] ${label} pair ${surface} / ${foreground} is
- [theme-contract] renderer theme must use the shared generate
- [theme-contract] renderer stylesheet ${fileName} cannot use
- [theme-contract] renderer TypeScript source ${fileName} cann
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/2cf7e3047666a9d5.
Report an issue: GitHub.