{"record":{"id":"07749178140369fe","repo":"tailwindlabs/tailwindcss","slug":"plugin-must-have-a-path","errorCode":null,"errorMessage":"`@plugin` must have a path.","messagePattern":"`@plugin` must have a path\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tailwindcss/src/compat/apply-compat-hooks.ts","lineNumber":66,"sourceCode":"    id: string\n    base: string\n    reference: boolean\n    src: SourceLocation | undefined\n  }[] = []\n\n  walk(ast, (node, _ctx) => {\n    if (node.kind !== 'at-rule') return\n    let ctx = cssContext(_ctx)\n\n    // Collect paths from `@plugin` at-rules\n    if (node.name === '@plugin') {\n      if (ctx.parent !== null) {\n        throw new Error('`@plugin` cannot be nested.')\n      }\n\n      let pluginPath = node.params.slice(1, -1)\n      if (pluginPath.length === 0) {\n        throw new Error('`@plugin` must have a path.')\n      }\n\n      let options: CssPluginOptions = {}\n\n      for (let decl of node.nodes ?? []) {\n        if (decl.kind !== 'declaration') {\n          throw new Error(\n            `Unexpected \\`@plugin\\` option:\\n\\n${toCss([decl])}\\n\\n\\`@plugin\\` options must be a flat list of declarations.`,\n          )\n        }\n\n        if (decl.value === undefined) continue\n\n        // Parse the declaration value as a primitive type\n        // These are the same primitive values supported by JSON\n        let value: CssPluginOptions[keyof CssPluginOptions] = decl.value\n\n        let parts = segment(value, ',').map((part) => {","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/tailwindlabs/tailwindcss/blob/16e94cbf7f965c5ad697e90e940b5e178efad67c/packages/tailwindcss/src/compat/apply-compat-hooks.ts#L48-L84","documentation":"Thrown when an `@plugin` at-rule has params that, after stripping the surrounding quotes (`node.params.slice(1, -1)`), are zero-length. Tailwind needs a module path to load, so an empty path is rejected.","triggerScenarios":"Writing `@plugin;` or `@plugin \"\";`. The slice removes the quote characters; if nothing remains, the guard fires.","commonSituations":"Typo or incomplete edit leaving the path empty; templating that emits `@plugin \"\";` when a variable is undefined.","solutions":["Provide a valid module path: `@plugin \"./my-plugin.js\";`.","If using a template variable, ensure it resolves to a non-empty path before emitting the at-rule."],"exampleFix":"// before\n@plugin \"\";\n// after\n@plugin \"./my-plugin.js\";","handlingStrategy":"validation","validationCode":"function assertPluginHasPath(node) {\n  if (node.name === '@plugin' && node.params.slice(1, -1).length === 0) {\n    throw new Error('@plugin requires a non-empty path');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use snippets/templates that always include a sample path for `@plugin`.","Lint against empty `@plugin` statements in CI."],"tags":["tailwind","plugin","at-rule","config"],"backgroundTag":null,"analyzedSha":"16e94cbf7f965c5ad697e90e940b5e178efad67c","analyzedAt":"2026-08-12T06:02:42.469Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}