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

  1. Move the dynamic portion to the end as a single `-*`, e.g. `@utility icon-*` and encode other dimensions via the body or separate utilities.
  2. Drop the `*` if the name should be static.
  3. 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

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


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