tailwindlabs/tailwindcss · error · Error

`@source` cannot have a body.

Error message

`@source` cannot have a body.

What it means

Thrown when an `@source` at-rule has any child nodes (`node.nodes.length > 0`). `@source` is a statement-style at-rule that takes its arguments in the prelude (`@source "./**/*.html"`); giving it a curly-brace body is structurally invalid and is rejected before the path is even inspected.

Source

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

          } 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.`,
            )
          }
        }

        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()

View on GitHub (pinned to 16e94cbf7f)

Solutions

  1. Remove the body block — keep `@source` as a single statement ending with `;`.
  2. If you meant to define a custom utility, use `@utility name { ... }` instead.
  3. If you meant to register a custom variant with a body, use `@custom-variant name { ... }`.

Example fix

/* before */
@source "./src/**/*.html" {
  /* ... */
}

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

Strategy: validation

Validate before calling

// Fail any @source that carries a body.
import postcss from 'postcss'

function validateSourceHasNoBody(css: string): string[] {
  const errors: string[] = []
  postcss.parse(css).walkAtRules('@source', (rule) => {
    if (rule.nodes.length > 0) {
      errors.push(`@source ${rule.params} must not have a body`)
    }
  })
  return errors
}

Prevention

When it happens

Trigger: Writing `@source "./src/**/*.html" { color: red; }` or any `@source ... { ... }` with a body block.

Common situations: Confusing `@source` (file globs for candidate scanning) with `@utility`/`@variant` (which have bodies); editor auto-completing a `{ }` block after the at-rule.

Related errors


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