tailwindlabs/tailwindcss · error · Error

`@source` cannot be nested.

Error message

`@source` cannot be nested.

What it means

Thrown when an `@source` at-rule is encountered with a non-null parent (`ctx.parent !== null`). Like `@utility`, `@source` is a top-level directive; nesting it under `@media`, a selector rule, or any other block is rejected immediately after the no-body check.

Source

Thrown at packages/tailwindcss/src/index.ts:264

          }
        }

        throw new Error(
          `\`@utility ${node.params}\` defines an invalid utility name. Utilities should be alphanumeric and start with a lowercase letter.`,
        )
      }

      customUtilities.push(utility)
    }

    // Collect paths from `@source` at-rules
    if (node.name === '@source') {
      if (node.nodes.length > 0) {
        throw new Error('`@source` cannot have a body.')
      }

      if (ctx.parent !== null) {
        throw new Error('`@source` cannot be nested.')
      }

      let not = false
      let inline = false
      let path = node.params

      if (path[0] === 'n' && path.startsWith('not ')) {
        not = true
        path = path.slice(4)
      }

      if (path[0] === 'i' && path.startsWith('inline(')) {
        inline = true
        path = path.slice(7, -1).trim()
      }

      if (
        (path[0] === '"' && path[path.length - 1] !== '"') ||

View on GitHub (pinned to 16e94cbf7f)

Solutions

  1. Move the `@source` statement to the top level of the stylesheet.
  2. Use globs to narrow scope rather than structural nesting: `@source "./theme/**/*.html"`.
  3. Use `@source not("...")` to exclude paths instead of wrapping in conditional rules.

Example fix

/* before */
.theme-dark {
  @source "./dark/**/*.html";
}

/* after */
@source "./dark/**/*.html";
Defensive patterns

Strategy: validation

Validate before calling

// Reject nested @source the same way the library does.
import postcss from 'postcss'

function validateSourceIsTopLevel(css: string): string[] {
  const errors: string[] = []
  postcss.parse(css).walkAtRules('@source', (rule) => {
    if (rule.parent && rule.parent.type !== 'root') {
      errors.push(`@source ${rule.params} must be at the top level`)
    }
  })
  return errors
}

Prevention

When it happens

Trigger: Placing `@source` inside `@media`, inside a selector, or inside another at-rule, e.g. `.theme { @source "./theme/**/*.html"; }`.

Common situations: Trying to scope source discovery to a sub-tree; preprocessors that wrap content; refactors that indent directives.

Related errors


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