tailwindlabs/tailwindcss · error · Error

The prefix "${themePrefix}" is invalid. Prefixes must be low

Error message

The prefix "${themePrefix}" is invalid. Prefixes must be lowercase ASCII letters (a-z) only.

What it means

Thrown when an `@theme` rule sets `prefix(...)` and the extracted prefix fails `IS_VALID_PREFIX = /^[a-z]+$/`. Unlike variant names, theme prefixes are intentionally restrictive: lowercase ASCII letters only, no digits, dashes, underscores, or mixed case. The check fires before the prefix is assigned to the theme.

Source

Thrown at packages/tailwindcss/src/index.ts:560

      return WalkAction.Continue
    }

    // Handle `@theme`
    if (node.name === '@theme') {
      let [themeOptions, themePrefix] = parseThemeOptions(node.params)

      features |= Features.AtTheme

      if (ctx.context.reference) {
        themeOptions |= ThemeOptions.REFERENCE
      }

      if (themePrefix) {
        if (!IS_VALID_PREFIX.test(themePrefix)) {
          throw new Error(
            `The prefix "${themePrefix}" is invalid. Prefixes must be lowercase ASCII letters (a-z) only.`,
          )
        }

        theme.prefix = themePrefix
      }

      // Record all custom properties in the `@theme` declaration
      walk(node.nodes, (child) => {
        // Collect `@keyframes` rules to re-insert with theme variables later,
        // since the `@theme` rule itself will be removed.
        if (child.kind === 'at-rule' && child.name === '@keyframes') {
          theme.addKeyframes(child)
          return WalkAction.Skip
        }

        if (child.kind === 'comment') return
        if (child.kind === 'declaration' && child.property.startsWith('--')) {
          theme.add(unescape(child.property), child.value ?? '', themeOptions, child.src)
          return

View on GitHub (pinned to 16e94cbf7f)

Solutions

  1. Use lowercase ASCII letters only: `@theme prefix(tw)` (Tailwind appends the `-` separator automatically at use time).
  2. Drop digits and dashes from the prefix value.
  3. If you need no prefix, omit the `prefix(...)` parameter entirely.

Example fix

/* before */
@theme prefix(tw-) {
  --color-brand: #007;
}

/* after */
@theme prefix(tw) {
  --color-brand: #007;
} /* use as tw-color-brand */
Defensive patterns

Strategy: type-guard

Type guard

// Mirror the library's IS_VALID_PREFIX (index.ts:40).
const IS_VALID_PREFIX = /^[a-z]+$/

function isValidThemePrefix(prefix: string): boolean {
  return IS_VALID_PREFIX.test(prefix)
}

Prevention

When it happens

Trigger: Writing `@theme prefix(tw-)` (dash), `@theme prefix(TW)` (uppercase), `@theme prefix(tw2)` (digit), or `@theme prefix()` (empty).

Common situations: Carrying over a v3 prefix like `tw-` that includes a trailing dash; assuming prefix rules match variant-name rules; using an empty prefix by mistake.

Related errors


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