{"record":{"id":"d07d64746ee033dc","repo":"tailwindlabs/tailwindcss","slug":"the-prefix-themeprefix-is-invalid-prefixes-m","errorCode":null,"errorMessage":"The prefix \"${themePrefix}\" is invalid. Prefixes must be lowercase ASCII letters (a-z) only.","messagePattern":"The prefix \"(.+?)\" is invalid\\. Prefixes must be lowercase ASCII letters \\(a-z\\) only\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tailwindcss/src/index.ts","lineNumber":560,"sourceCode":"\n      return WalkAction.Continue\n    }\n\n    // Handle `@theme`\n    if (node.name === '@theme') {\n      let [themeOptions, themePrefix] = parseThemeOptions(node.params)\n\n      features |= Features.AtTheme\n\n      if (ctx.context.reference) {\n        themeOptions |= ThemeOptions.REFERENCE\n      }\n\n      if (themePrefix) {\n        if (!IS_VALID_PREFIX.test(themePrefix)) {\n          throw new Error(\n            `The prefix \"${themePrefix}\" is invalid. Prefixes must be lowercase ASCII letters (a-z) only.`,\n          )\n        }\n\n        theme.prefix = themePrefix\n      }\n\n      // Record all custom properties in the `@theme` declaration\n      walk(node.nodes, (child) => {\n        // Collect `@keyframes` rules to re-insert with theme variables later,\n        // since the `@theme` rule itself will be removed.\n        if (child.kind === 'at-rule' && child.name === '@keyframes') {\n          theme.addKeyframes(child)\n          return WalkAction.Skip\n        }\n\n        if (child.kind === 'comment') return\n        if (child.kind === 'declaration' && child.property.startsWith('--')) {\n          theme.add(unescape(child.property), child.value ?? '', themeOptions, child.src)\n          return","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/tailwindlabs/tailwindcss/blob/16e94cbf7f965c5ad697e90e940b5e178efad67c/packages/tailwindcss/src/index.ts#L542-L578","documentation":"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.","triggerScenarios":"Writing `@theme prefix(tw-)` (dash), `@theme prefix(TW)` (uppercase), `@theme prefix(tw2)` (digit), or `@theme prefix()` (empty).","commonSituations":"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.","solutions":["Use lowercase ASCII letters only: `@theme prefix(tw)` (Tailwind appends the `-` separator automatically at use time).","Drop digits and dashes from the prefix value.","If you need no prefix, omit the `prefix(...)` parameter entirely."],"exampleFix":"/* before */\n@theme prefix(tw-) {\n  --color-brand: #007;\n}\n\n/* after */\n@theme prefix(tw) {\n  --color-brand: #007;\n} /* use as tw-color-brand */","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Mirror the library's IS_VALID_PREFIX (index.ts:40).\nconst IS_VALID_PREFIX = /^[a-z]+$/\n\nfunction isValidThemePrefix(prefix: string): boolean {\n  return IS_VALID_PREFIX.test(prefix)\n}","tryCatchPattern":null,"preventionTips":["Restrict prefixes to lowercase ASCII letters only — no dashes, digits, or uppercase.","Tailwind adds the `-` separator automatically; do not include it in `prefix(...)`.","Share the `IS_VALID_PREFIX` regex across lint and runtime so they agree."],"tags":["at-theme","prefix","naming","regex"],"backgroundTag":null,"analyzedSha":"16e94cbf7f965c5ad697e90e940b5e178efad67c","analyzedAt":"2026-08-12T06:02:42.469Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}