{"record":{"id":"411778b54340e6f7","repo":"tailwindlabs/tailwindcss","slug":"theme-blocks-must-only-contain-custom-propertie","errorCode":null,"errorMessage":"`@theme` blocks must only contain custom properties or `@keyframes`.\n\n${snippet}","messagePattern":"`@theme` blocks must only contain custom properties or `@keyframes`\\.\n\n(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tailwindcss/src/index.ts","lineNumber":586,"sourceCode":"        // Collect `@keyframes` rules to re-insert with theme variables later,\n        // since the `@theme` rule itself will be removed.\n        if (child.kind === 'at-rule' && child.name === '@keyframes') {\n          theme.addKeyframes(child)\n          return WalkAction.Skip\n        }\n\n        if (child.kind === 'comment') return\n        if (child.kind === 'declaration' && child.property.startsWith('--')) {\n          theme.add(unescape(child.property), child.value ?? '', themeOptions, child.src)\n          return\n        }\n\n        let snippet = toCss([atRule(node.name, node.params, [child])])\n          .split('\\n')\n          .map((line, idx, all) => `${idx === 0 || idx >= all.length - 2 ? ' ' : '>'} ${line}`)\n          .join('\\n')\n\n        throw new Error(\n          `\\`@theme\\` blocks must only contain custom properties or \\`@keyframes\\`.\\n\\n${snippet}`,\n        )\n      })\n\n      // Keep a reference to the first `@theme` rule to update with the full\n      // theme later, and delete any other `@theme` rules.\n      if (!firstThemeRule) {\n        firstThemeRule = styleRule(':root, :host', [])\n        firstThemeRule.src = node.src\n        return WalkAction.ReplaceSkip(firstThemeRule)\n      } else {\n        return WalkAction.ReplaceSkip([])\n      }\n    }\n  })\n\n  let designSystem = buildDesignSystem(theme, utilitiesNode?.src)\n","sourceCodeStart":568,"sourceCodeEnd":604,"githubUrl":"https://github.com/tailwindlabs/tailwindcss/blob/16e94cbf7f965c5ad697e90e940b5e178efad67c/packages/tailwindcss/src/index.ts#L568-L604","documentation":"Thrown while walking an `@theme` block when a child node is neither a comment, nor a `--`-prefixed declaration, nor an `@keyframes` at-rule. `@theme` is a token container: it may only hold custom properties (`--*`) and `@keyframes` definitions (which Tailwind re-inserts alongside the theme variables). Any other construct — a selector rule, a plain declaration, a non-keyframes at-rule — is rejected with a CSS snippet of the offending node marked with `>`.","triggerScenarios":"Putting a selector rule (`body { ... }`), a non-custom property (`color: red;`), or a non-keyframes at-rule (`@media ...`) inside `@theme { ... }`.","commonSituations":"Treating `@theme` like a generic CSS scope; refactoring a base stylesheet and dropping rules into the wrong block; migrating v3 `@layer base` content into `@theme`.","solutions":["Move non-token rules out of `@theme` into `@layer base` or the top level of the stylesheet.","Ensure every declaration inside `@theme` begins with `--` (e.g. `--color-brand: #007;`).","Keep only `@keyframes` at-rules alongside the custom properties — other at-rules are not permitted."],"exampleFix":"/* before */\n@theme {\n  --color-brand: #007;\n  body { margin: 0; }\n}\n\n/* after */\n@theme {\n  --color-brand: #007;\n}\n@layer base {\n  body { margin: 0; }\n}","handlingStrategy":"validation","validationCode":"// Verify every @theme child is a --declaration, @keyframes, or comment.\nimport postcss from 'postcss'\n\nfunction validateThemeChildren(css: string): string[] {\n  const errors: string[] = []\n  postcss.parse(css).walkAtRules('@theme', (rule) => {\n    rule.each((node) => {\n      if (node.type === 'comment') return\n      if (node.type === 'decl' && node.prop.startsWith('--')) return\n      if (node.type === 'atrule' && (node as postcss.AtRule).name === 'keyframes') return\n      errors.push(`Invalid node in @theme: ${node.type} ${(node as any).selector || (node as any).prop || (node as any).name}`)\n    })\n  })\n  return errors\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep `@theme` blocks for tokens only — move base/component CSS to `@layer base` or the top level.","Prefix every declaration inside `@theme` with `--`.","Lint `@theme` contents in CI to catch misplaced rules."],"tags":["at-theme","structure","tokens","validation"],"backgroundTag":null,"analyzedSha":"16e94cbf7f965c5ad697e90e940b5e178efad67c","analyzedAt":"2026-08-12T06:02:42.469Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}