{"record":{"id":"3fa61641c8d44c38","repo":"tailwindlabs/tailwindcss","slug":"custom-variant-name-defines-an-invalid-varia","errorCode":null,"errorMessage":"`@custom-variant ${name}` defines an invalid variant name. Variants should only contain alphanumeric, dashes, or underscore characters and start with a lowercase letter or number.","messagePattern":"`@custom-variant (.+?)` defines an invalid variant name\\. Variants should only contain alphanumeric, dashes, or underscore characters and start with a lowercase letter or number\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tailwindcss/src/index.ts","lineNumber":360,"sourceCode":"      }\n\n      // Collect all the `@variant` at-rules, we will replace them later once\n      // all variants are registered in the system.\n      else {\n        variantNodes.push(node)\n      }\n    }\n\n    // Register custom variants from `@custom-variant` at-rules\n    if (node.name === '@custom-variant') {\n      if (ctx.parent !== null) {\n        throw new Error('`@custom-variant` cannot be nested.')\n      }\n\n      let [name, selector] = segment(node.params, ' ')\n\n      if (!IS_VALID_VARIANT_NAME.test(name)) {\n        throw new Error(\n          `\\`@custom-variant ${name}\\` defines an invalid variant name. Variants should only contain alphanumeric, dashes, or underscore characters and start with a lowercase letter or number.`,\n        )\n      }\n\n      if (node.nodes.length > 0 && selector) {\n        throw new Error(`\\`@custom-variant ${name}\\` cannot have both a selector and a body.`)\n      }\n\n      // Variants with a selector, but without a body, e.g.: `@custom-variant hocus (&:hover, &:focus);`\n      if (node.nodes.length === 0) {\n        if (!selector) {\n          throw new Error(`\\`@custom-variant ${name}\\` has no selector or body.`)\n        }\n\n        let selectors = segment(selector.slice(1, -1), ',')\n        if (selectors.length === 0 || selectors.some((selector) => selector.trim() === '')) {\n          throw new Error(\n            `\\`@custom-variant ${name} (${selectors.join(',')})\\` selector is invalid.`,","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/tailwindlabs/tailwindcss/blob/16e94cbf7f965c5ad697e90e940b5e178efad67c/packages/tailwindcss/src/index.ts#L342-L378","documentation":"Thrown when the first space-delimited token of `@custom-variant`'s params fails `IS_VALID_VARIANT_NAME = /^@?[a-z0-9][a-zA-Z0-9_-]*(?<![_-])$/`. Variant names must start with a lowercase letter or digit, contain only alphanumerics, dashes, or underscores, and must not end with `-` or `_`.","triggerScenarios":"Naming a variant `@custom-variant Hocus`, `@custom-variant my variant`, `@custom-variant foo-` (trailing dash), `@custom-variant 1foo` is allowed (starts with digit) but `@custom-variant .foo` is not.","commonSituations":"Using CamelCase or PascalCase by convention; trailing dash from a partial rename; embedding special characters copied from a selector.","solutions":["Rename to start with `a-z0-9` and contain only `[a-zA-Z0-9_-]` without a trailing `-` or `_`: `@custom-variant hocus (...)`.","Convert PascalCase to kebab-case: `Hocus` → `hocus`.","Strip trailing dashes/underscores."],"exampleFix":"/* before */\n@custom-variant Hocus_ (&:hover, &:focus);\n\n/* after */\n@custom-variant hocus (&:hover, &:focus);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Identical to the library's IS_VALID_VARIANT_NAME (variants.ts:27).\nconst IS_VALID_VARIANT_NAME = /^@?[a-z0-9][a-zA-Z0-9_-]*(?<![_-])$/\n\nfunction isValidVariantName(name: string): boolean {\n  return IS_VALID_VARIANT_NAME.test(name)\n}","tryCatchPattern":null,"preventionTips":["Start variant names with a lowercase letter or digit; never uppercase.","Avoid trailing `-` or `_`; prefer kebab-case (`my-variant`).","Share the `IS_VALID_VARIANT_NAME` regex in a constants file so lint and runtime agree."],"tags":["at-custom-variant","naming","validation","regex"],"backgroundTag":null,"analyzedSha":"16e94cbf7f965c5ad697e90e940b5e178efad67c","analyzedAt":"2026-08-12T06:02:42.469Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}