tailwindlabs/tailwindcss · error · Error
`@utility` cannot be nested.
Error message
`@utility` cannot be nested.
What it means
Thrown when an `@utility` at-rule is encountered while walking the AST and the current node has a non-null parent (`ctx.parent !== null`). Tailwind requires `@utility` blocks to live at the stylesheet's top level; nesting them inside `@media`, another `@utility`, or any other rule is a structural error detected before the utility body is even parsed.
Source
Thrown at packages/tailwindcss/src/index.ts:226
) {
throw new Error('`source(…)` paths must be quoted.')
}
root = {
base: (ctx.context.sourceBase as string) ?? (ctx.context.base as string),
pattern: path.slice(1, -1),
}
}
}
utilitiesNode = node
features |= Features.Utilities
}
// Collect custom `@utility` at-rules
if (node.name === '@utility') {
if (ctx.parent !== null) {
throw new Error('`@utility` cannot be nested.')
}
if (node.nodes.length === 0) {
throw new Error(
`\`@utility ${node.params}\` is empty. Utilities should include at least one property.`,
)
}
let utility = createCssUtility(node)
if (utility === null) {
if (!node.params.endsWith('-*')) {
if (node.params.endsWith('*')) {
throw new Error(
`\`@utility ${node.params}\` defines an invalid utility name. A functional utility must end in \`-*\`.`,
)
} else if (node.params.includes('*')) {
throw new Error(
`\`@utility ${node.params}\` defines an invalid utility name. The dynamic portion marked by \`-*\` must appear once at the end.`,View on GitHub (pinned to 16e94cbf7f)
Solutions
- Move the `@utility` block to the top level of the stylesheet (out of any parent rule).
- If you need responsive behavior, apply the variant at the call site (`print:foo`) rather than nesting the definition under `@media`.
- If you were grouping utilities for organization, use comments or separate files instead of a wrapping rule.
Example fix
/* before */
@media print {
@utility hide-print { display: none; }
}
/* after */
@utility hide-print { display: none; }
/* apply via: <div class="print:hidden"> — or keep print styles inside @media without @utility */ Defensive patterns
Strategy: validation
Validate before calling
// Lightweight CSS walker that fails if @utility has a parent rule.
import postcss from 'postcss'
function validateNoNestedUtility(css: string): string[] {
const errors: string[] = []
postcss.parse(css).walkAtRules('@utility', (rule) => {
if (rule.parent && rule.parent.type !== 'root') {
errors.push(`@utility ${rule.params} is nested under ${rule.parent.type}`)
}
})
return errors
} Prevention
- Keep all `@utility` blocks at column 0 of the stylesheet.
- Run a pre-compile lint pass that rejects `@utility` inside any non-root parent.
- Use variants at the call site (`md:foo`) instead of nesting definitions under media queries.
When it happens
Trigger: Placing `@utility` inside `@media (...)`, inside another `@utility`, or inside any selector rule. E.g. `@media print { @utility foo { color: red } }`.
Common situations: Migrating component CSS where utilities were defined inside scoped blocks; tooling or preprocessors that auto-wrap rules; hand-editing a CSS file and indenting `@utility` under a media query.
Related errors
- `@source` cannot be nested.
- `@custom-variant` cannot be nested.
- `@plugin` cannot be nested.
- `@config` cannot be nested.
- `@utility ${node.params}` is empty. Utilities should include
AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12).
Data as JSON: /api/errors/54e075539031ec51.
Report an issue: GitHub.