tailwindlabs/tailwindcss · error · Error
`@utility ${node.params}` is empty. Utilities should include
Error message
`@utility ${node.params}` is empty. Utilities should include at least one property. What it means
Thrown when an `@utility` at-rule has zero child nodes (`node.nodes.length === 0`). Tailwind requires every utility to declare at least one CSS property so it produces output; an empty block is almost always a typo or an unfinished edit. The check runs after the nesting guard and before `createCssUtility`.
Source
Thrown at packages/tailwindcss/src/index.ts:230
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
- Add at least one CSS declaration inside the block, e.g. `@utility card { padding: 1rem; }`.
- If the utility is no longer needed, remove the entire `@utility` at-rule.
- Re-check that your editor/CI did not strip the body during formatting.
Example fix
/* before */
@utility card { }
/* after */
@utility card {
padding: 1rem;
border-radius: 0.5rem;
} Defensive patterns
Strategy: validation
Validate before calling
// Reject empty @utility blocks before compiling.
import postcss from 'postcss'
function validateUtilityHasBody(css: string): string[] {
const errors: string[] = []
postcss.parse(css).walkAtRules('@utility', (rule) => {
if (rule.nodes.length === 0) {
errors.push(`@utility ${rule.params} is empty`)
}
})
return errors
} Prevention
- Treat `@utility name {}` as a typo in code review.
- Add an editor snippet that always inserts at least one placeholder declaration.
- Lint for empty at-rule blocks in CI.
When it happens
Trigger: Writing `@utility card { }` with no declarations, or a block containing only comments/whitespace that parse to zero nodes.
Common situations: Stubbing out a utility placeholder and forgetting to fill it; deleting the body during a refactor and leaving the at-rule behind; copy-paste that dropped the inner rules.
Related errors
- `@utility ${node.params}` defines an invalid utility name. U
- The prefix "${resolvedConfig.prefix}" is invalid. Prefixes m
- `addVariant('${name}')` defines an invalid variant name. Var
- `matchUtilities({ '${name}' : … })` defines an invalid utili
- `@utility` cannot be nested.
AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12).
Data as JSON: /api/errors/a39ffacb448585b7.
Report an issue: GitHub.