tailwindlabs/tailwindcss · error · Error
`@utility ${node.params}` defines an invalid utility name. U
Error message
`@utility ${node.params}` defines an invalid utility name. Utilities should be alphanumeric and start with a lowercase letter. What it means
Terminal fallback in the `createCssUtility === null` chain: the params contain no offending `*` placement but still fail the strict utility-name validation (start with a lowercase letter, alphanumeric + dashes). Typical offenders: leading uppercase, leading digit, embedded spaces, or disallowed characters.
Source
Thrown at packages/tailwindcss/src/index.ts:249
`\`@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.`,
)
}
}
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 = falseView on GitHub (pinned to 16e94cbf7f)
Solutions
- Rename to start with a lowercase letter and use only `a-z0-9-`: `@utility foo-bar`.
- Replace underscores with dashes: `foo_bar` → `foo-bar`.
- For functional utilities keep exactly one trailing `-*`: `icon-*` (not `icon-*-*`).
Example fix
/* before */
@utility Card_Primary { ... }
/* after */
@utility card-primary { ... } Defensive patterns
Strategy: type-guard
Type guard
// Full utility-name guard covering the terminal fallback.
// Static: lowercase letter, then alphanumerics/dashes. Functional: same, plus single trailing -*.
const STATIC_UTILITY = /^[a-z][a-zA-Z0-9-]*$/
const FUNCTIONAL_UTILITY = /^[a-z][a-zA-Z0-9-]*-\*$/
function isValidUtilityName(name: string): boolean {
return STATIC_UTILITY.test(name) || FUNCTIONAL_UTILITY.test(name)
} Prevention
- Adopt kebab-case starting with a lowercase letter for every utility name.
- Reject underscores, spaces, and uppercase in code review.
- Avoid multi-wildcard names like `-*-*` — split into separate utilities.
When it happens
Trigger: Naming a utility `@utility Foo`, `@utility 3col`, `@utility foo bar`, `@utility foo_bar`, or `@utility foo-*-*` (the last ends with `-*` so it bypasses the `*` checks and lands here because the double wildcard is invalid).
Common situations: Importing BEM/kebab-snake names that use underscores; capitalizing utility names by convention; copy-paste that introduces a space or stray character.
Related errors
- `@utility ${node.params}` is empty. Utilities should include
- `@utility ${node.params}` defines an invalid utility name. A
- `@utility ${node.params}` defines an invalid utility name. T
- `@custom-variant ${name}` defines an invalid variant name. V
- The prefix "${resolvedConfig.prefix}" is invalid. Prefixes m
AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12).
Data as JSON: /api/errors/8b53552c329a408f.
Report an issue: GitHub.