CherryHQ/cherry-studio · error · Error
[theme-contract] foundation ${declaration.name} cannot depen
Error message
[theme-contract] foundation ${declaration.name} cannot depend on upper-layer ${reference} What it means
Thrown by assertLayerDependencies when a foundation declaration's value references an upper-layer variable: a runtime input (--cs-theme-*), an official Shadcn variable (--background etc.), a product variable (--success etc.), a Tailwind adapter variable (--color-*), or a host-local variable (--app-*). Foundation is the lowest layer and may only reference other foundation variables; upward dependencies create ordering and coupling that break the layering model.
Source
Thrown at packages/ui/scripts/validate-theme-contract.ts:252
['tokens/spacing.css', sources.spacing],
['tokens/radius.css', sources.radius],
['tokens/typography.css', sources.typography]
]
for (const [sourceName, source] of foundationEntries) {
for (const declaration of extractDeclarations(source, sourceName)) {
if (declaration.name.startsWith(runtimeVariablePrefix)) {
throw new Error(`[theme-contract] foundation cannot declare runtime input ${declaration.name}`)
}
for (const reference of extractReferences(declaration.value, declaration.source)) {
if (
reference.startsWith(runtimeVariablePrefix) ||
officialVariables.has(reference) ||
productVariables.has(reference) ||
reference.startsWith('--color-') ||
reference.startsWith('--app-')
) {
throw new Error(`[theme-contract] foundation ${declaration.name} cannot depend on upper-layer ${reference}`)
}
}
}
}
for (const declaration of extractDeclarations(sources.themeInput, 'theme-input.css')) {
if (!runtimeVariables.has(declaration.name)) {
throw new Error(`[theme-contract] theme-input.css declares unregistered runtime input ${declaration.name}`)
}
for (const reference of extractReferences(declaration.value, declaration.source)) {
if (officialVariables.has(reference) || productVariables.has(reference) || reference.startsWith('--color-')) {
throw new Error(`[theme-contract] runtime input ${declaration.name} cannot depend on upper-layer ${reference}`)
}
if (reference.startsWith('--app-')) {
throw new Error(`[theme-contract] runtime input ${declaration.name} cannot depend on host-local ${reference}`)
}
}
}View on GitHub (pinned to 726446b54c)
Solutions
- Re-point the foundation variable at another foundation-layer value (--cs-*, primitive, or a literal).
- If the dependency is legitimately upward, move the declaration into the higher layer that owns the dependency (e.g. shadcn.css may reference foundation; product.css may reference shadcn).
- Re-run `pnpm --filter @cherrystudio/ui theme:check`.
Example fix
// before (tokens/colors/providers.css) --cs-primary: var(--background); // after — foundation only references foundation --cs-primary: var(--cs-brand-500);
Defensive patterns
Strategy: validation
Validate before calling
// Guard: foundation declarations must only reference other foundation names.
const foundationNames = new Set([...sources.primitiveColors.matchAll(/(--[a-z0-9-]+)\s*:/g)].map((m) => m[1]))
const upperLayer = (ref: string) => ref.startsWith('--cs-theme-') || ref.startsWith('--color-') || ref.startsWith('--app-')
for (const s of [sources.primitiveColors, sources.providerColors, sources.statusLegacyColors, sources.spacing, sources.radius, sources.typography]) {
for (const [, ref] of s.matchAll(/var\(\s*(--[a-z0-9-]+)/g)) {
if (upperLayer(ref)) throw new Error(`foundation references upper layer ${ref}`)
}
} Try / catch
try {
validateThemeContractSources(sources)
} catch (error) {
if (error instanceof Error && /foundation .* cannot depend on upper-layer/.test(error.message)) {
console.error(error.message)
process.exitCode = 1
return
}
throw error
} Prevention
- Foundation is the bottom of the stack: only literals and other foundation vars allowed.
- If you need a value to adapt to an upper layer, move the declaration up, do not pull the upper reference down.
- Run theme:check after touching any tokens/*.css file.
When it happens
Trigger: Setting `--cs-primary: var(--background);` in providers.css (Shadcn dep); `--cs-primary: var(--success);` (product dep); `--cs-primary: var(--cs-theme-primary);` (runtime input dep); `--cs-foo: var(--color-red-500);` (Tailwind adapter dep).
Common situations: Trying to make a foundation token 'adapt to theme' by pointing it at a higher-layer variable; reintroducing an old coupling during a refactor.
Related errors
- [theme-contract] foundation cannot declare runtime input ${d
- [theme-contract] runtime input ${declaration.name} cannot de
- [theme-contract] runtime input ${declaration.name} cannot de
- [theme-contract] shadcn.css cannot own runtime input ${decla
- [theme-contract] Shadcn ${declaration.name} cannot depend on
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/36c0f134da71f422.
Report an issue: GitHub.