tailwindlabs/tailwindcss · error · Error
The rule `@apply ${list}` must not have a body.
Error message
The rule `@apply ${list}` must not have a body. What it means
Thrown when an `@apply` at-rule that references normal utility classes also contains a declaration body (i.e. `child.nodes.length > 0`). Tailwind v4 treats `@apply` as a pure substitution: it expands into the utility's CSS and cannot also hold its own declarations, so a body is rejected. The error lists the offending utility idents so the offending rule is identifiable.
Source
Thrown at packages/tailwindcss/src/apply.ts:209
// If we find a dashed ident *here* it means that someone is trying
// to use mixins and our `@apply` behavior together.
//
// This is invalid and the rules must be written separately. Let the
// user know they need to move them into a separate rule.
let list = dashedIdents.join(' ')
throw new Error(
`You cannot use \`@apply\` with both mixins and utilities. Please move \`@apply ${list}\` into a separate rule.`,
)
}
let hasBody = child.nodes.length > 0
if (hasBody && normalIdents.length) {
let list = normalIdents.join(' ')
throw new Error(`The rule \`@apply ${list}\` must not have a body.`)
}
// Replace the `@apply` rule with the actual utility classes
{
// Parse the candidates to an AST that we can replace the `@apply` rule
// with.
let candidates = Object.keys(candidateOffsets)
let compiled = compileCandidates(candidates, designSystem, {
respectImportant: false,
onInvalidCandidate: (candidate) => {
// When using prefix, make sure prefix is used in candidate
if (designSystem.theme.prefix && !candidate.startsWith(designSystem.theme.prefix)) {
throw new Error(
`Cannot apply unprefixed utility class \`${candidate}\`. Did you mean \`${designSystem.theme.prefix}:${candidate}\`?`,
)
}
// When the utility is blocklisted, let the user knowView on GitHub (pinned to 16e94cbf7f)
Solutions
- Remove the body from the `@apply` rule and move those declarations into a sibling rule or wrap the `@apply` in an outer rule that also holds them.
- If you need media-query scoping, put `@apply` inside a `@media` block instead of putting the media query inside `@apply`.
- If you intended a CSS-mixin `@apply --foo;`, ensure it is the only content of the rule (dashed idents alone skip this check).
Example fix
// before
.btn {
@apply px-4 py-2 {
color: red;
}
}
// after
.btn {
@apply px-4 py-2;
color: red;
} Defensive patterns
Strategy: validation
Validate before calling
// Before writing CSS, ensure no @apply with utility idents has a body.
function assertApplyHasNoBody(css) {
const re = /@apply\s+[^;{}]+\s*\{[^}]*\}/g;
const hits = css.match(re) ?? [];
const bad = hits.filter(h => !/^[\s\S]*--/.test(h.split('@apply')[1]));
if (bad.length) throw new Error('Move declarations out of @apply body: ' + bad.join('\n'));
}
// assertApplyHasNoBody(myCss); Prevention
- Lint `@apply` rules with a custom Stylelint rule forbidding a body when normal idents are present.
- Treat `@apply` as a statement terminated by `;`, never as a block.
When it happens
Trigger: Writing CSS like `@apply flex { color: red; }` — an `@apply` whose params are normal utility idents (not `--dashed` mixins) AND whose node list is non-empty. Only fires when `hasBody && normalIdents.length` is truthy after the dashed-ident/mixin check has passed.
Common situations: Migrating from v3 where `@apply` accepted trailing declarations; muscle-memory of writing `@apply p-4 { @media (min-width: 768px) { ... } }`; copy-pasting nested at-rules inside an `@apply` block.
Related errors
- Cannot apply unprefixed utility class `${candidate}`. Did yo
- Cannot apply utility class `${candidate}` because it has bee
- Cannot apply utility class `${candidate}` because the `${unk
- Cannot apply utility class `${candidate}` because the ${unkn
- Cannot apply unknown utility class `${candidate}`. Are you u
AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12).
Data as JSON: /api/errors/25a3e7b324339c7b.
Report an issue: GitHub.