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

  1. Re-point the foundation variable at another foundation-layer value (--cs-*, primitive, or a literal).
  2. 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).
  3. 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

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


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