{"record":{"id":"0f3595b3d5a785b3","repo":"tailwindlabs/tailwindcss","slug":"unexpected-plugin-option-tocss-decl","errorCode":null,"errorMessage":"Unexpected `@plugin` option:\n\n${toCss([decl])}\n\n`@plugin` options must be a flat list of declarations.","messagePattern":"Unexpected `@plugin` option:\n\n(.+?)\n\n`@plugin` options must be a flat list of declarations\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tailwindcss/src/compat/apply-compat-hooks.ts","lineNumber":73,"sourceCode":"    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) => {\n          part = part.trim()\n\n          if (part === 'null') {\n            return null\n          } else if (part === 'true') {\n            return true\n          } else if (part === 'false') {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/tailwindlabs/tailwindcss/blob/16e94cbf7f965c5ad697e90e940b5e178efad67c/packages/tailwindcss/src/compat/apply-compat-hooks.ts#L55-L91","documentation":"Thrown while parsing the body of an `@plugin` at-rule when one of its child nodes is not a `declaration`. `@plugin` options in CSS must be a flat list of declarations (key: value;), so nested at-rules, rules, or comments-as-nodes are rejected. The offending node is rendered via `toCss` for context.","triggerScenarios":"Writing `@plugin \"x.js\" { .foo { color: red } }` (a nested rule instead of a declaration) or nesting an `@media` inside `@plugin`. Fires for every child whose `kind !== 'declaration'`.","commonSituations":"Confusing `@plugin` option syntax with regular CSS nesting; copy-pasting a rule block where options should go.","solutions":["Replace non-declaration children with flat `key: value;` declarations.","Move any CSS rules out of the `@plugin` block into the stylesheet proper.","If you need complex plugin config, use a JS config file instead of `@plugin` options."],"exampleFix":"// before\n@plugin \"./typography.js\" {\n  .prose { color: red; }\n}\n// after\n@plugin \"./typography.js\" {\n  className: prose;\n}","handlingStrategy":"validation","validationCode":"function assertPluginOptionsFlat(node) {\n  for (const child of node.nodes ?? []) {\n    if (child.kind !== 'declaration') {\n      throw new Error(`@plugin option must be a declaration, got ${child.kind}`);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only use `key: value;` declarations inside `@plugin { }`.","Move real CSS rules outside the `@plugin` block."],"tags":["tailwind","plugin","at-rule","syntax"],"backgroundTag":null,"analyzedSha":"16e94cbf7f965c5ad697e90e940b5e178efad67c","analyzedAt":"2026-08-12T06:02:42.469Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}