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

  1. Move the `@utility` block to the top level of the stylesheet (out of any parent rule).
  2. If you need responsive behavior, apply the variant at the call site (`print:foo`) rather than nesting the definition under `@media`.
  3. 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

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


AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12). Data as JSON: /api/errors/54e075539031ec51. Report an issue: GitHub.