tailwindlabs/tailwindcss · error · Error
`@utility ${node.params}` defines an invalid utility name. T
Error message
`@utility ${node.params}` defines an invalid utility name. The dynamic portion marked by `-*` must appear once at the end. What it means
Thrown from the fallback chain when `createCssUtility(node)` returns null, the params do not end with `*`, but they contain a `*` somewhere in the middle. Because the dynamic marker must appear once at the end of a functional utility, an interior `*` (e.g. `foo-*-bar`, `*foo`, `a*b`) is ambiguous and rejected.
Source
Thrown at packages/tailwindcss/src/index.ts:245
}
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.`,
)
}
}
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) {View on GitHub (pinned to 16e94cbf7f)
Solutions
- Move the dynamic portion to the end as a single `-*`, e.g. `@utility icon-*` and encode other dimensions via the body or separate utilities.
- Drop the `*` if the name should be static.
- Split a multi-dimensional utility into several single-slot `@utility` rules.
Example fix
/* before */
@utility icon-*-${size} {
/* ... */
}
/* after */
@utility icon-* {
/* encode size another way, e.g. separate utilities icon-sm, icon-md */
} Defensive patterns
Strategy: validation
Validate before calling
// Catch a wildcard that is not at the end.
function validateNoInteriorWildcard(name: string): string | null {
if (name.includes('*') && !name.endsWith('*')) {
return `Wildcard in '${name}' must appear once at the end as -*`
}
return null
} Prevention
- Never place a `*` in the middle of a utility name; encode multi-dimensional variants as separate utilities.
- Lint `@utility` params for any `*` not in trailing `-*` position.
- Document your team's functional-utility naming convention in a CONTRIBUTING file.
When it happens
Trigger: Defining a functional utility with the wildcard anywhere other than the very end, e.g. `@utility icon-*-${size}`, `@utility *-hidden`, or `@utility cell-*-*` (the latter ends with `-*` so it actually falls through to error 66 — see notes).
Common situations: Trying to express multiple dynamic segments; copying glob patterns verbatim into `@utility` names.
Related errors
- `@utility ${node.params}` defines an invalid utility name. A
- `@utility ${node.params}` defines an invalid utility name. U
- `@utility` cannot be nested.
- `@utility ${node.params}` is empty. Utilities should include
- `@custom-variant ${name}` defines an invalid variant name. V
AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12).
Data as JSON: /api/errors/5139723259b6e12b.
Report an issue: GitHub.