CherryHQ/cherry-studio · error · Error
[theme-contract] theme-input.css declares unregistered runti
Error message
[theme-contract] theme-input.css declares unregistered runtime input ${declaration.name} What it means
Thrown by assertLayerDependencies when theme-input.css declares a --cs-theme-* variable whose unprefixed name is not in the RUNTIME_THEME_INPUT_TOKENS registry (currently ['primary', 'primary-foreground']). The runtime-input surface is a closed, explicitly-registered set so the host code that writes these variables at runtime stays synchronized with the contract.
Source
Thrown at packages/ui/scripts/validate-theme-contract.ts:260
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}`)
}
}
}
for (const declaration of extractDeclarations(sources.shadcn, 'shadcn.css')) {
if (declaration.name.startsWith(runtimeVariablePrefix)) {
throw new Error(`[theme-contract] shadcn.css cannot own runtime input ${declaration.name}`)
}
for (const reference of extractReferences(declaration.value, declaration.source)) {
if (productVariables.has(reference) || reference.startsWith('--color-') || reference.startsWith('--app-')) {
throw new Error(`[theme-contract] Shadcn ${declaration.name} cannot depend on product/adapter ${reference}`)View on GitHub (pinned to 726446b54c)
Solutions
- If the variable is a real new runtime input, register its unprefixed name (e.g. 'speculative') in RUNTIME_THEME_INPUT_TOKENS in scripts/theme-contract.ts and document it in variable-catalog.md.
- If it is not a runtime input, remove the declaration from theme-input.css (and if it belongs elsewhere, move it to the correct layer with the correct prefix).
- Re-run `pnpm --filter @cherrystudio/ui theme:check`.
Example fix
// before — theme-input.css declares an unregistered input
:root { --cs-theme-speculative: hotpink; }
// after (option A — register it)
// scripts/theme-contract.ts
export const RUNTIME_THEME_INPUT_TOKENS = ['primary', 'primary-foreground', 'speculative'] as const
// after (option B — remove the declaration) Defensive patterns
Strategy: validation
Validate before calling
// Ensure every --cs-theme-* declared in theme-input.css is registered.
const registered = new Set(RUNTIME_THEME_INPUT_TOKENS.map((t) => `--cs-theme-${t}`))
const unregistered = [...sources.themeInput.matchAll(/(--cs-theme-[a-z0-9-]+)\s*:/g)].map((m) => m[1]).filter((n) => !registered.has(n))
if (unregistered.length) throw new Error(`unregistered runtime inputs: ${unregistered.join(', ')}`) Try / catch
try {
validateThemeContractSources(sources)
} catch (error) {
if (error instanceof Error && /declares unregistered runtime input/.test(error.message)) {
console.error(error.message)
process.exitCode = 1
return
}
throw error
} Prevention
- Adding a --cs-theme-* declaration requires a matching entry in RUNTIME_THEME_INPUT_TOKENS in the same change.
- Keep the runtime-input surface intentionally tiny; prefer extending foundation --cs-* over new runtime inputs.
- Run theme:check after editing theme-input.css or scripts/theme-contract.ts.
When it happens
Trigger: Adding `--cs-theme-speculative: hotpink;` to theme-input.css without adding 'speculative' to RUNTIME_THEME_INPUT_TOKENS in scripts/theme-contract.ts; declaring a runtime input for an unregistered role.
Common situations: Adding a new themable role and forgetting the registry half of the change; leftover experimental declarations.
Related errors
- [theme-contract] product variable ${token} overlaps the offi
- [theme-contract] Tailwind product color ${token} is missing
- [theme-contract] compatibility color ${token} overlaps the c
- [theme-contract] shadcn.css declares unregistered Shadcn var
- [theme-contract] product.css declares unregistered product v
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/4e623956d94995d2.
Report an issue: GitHub.