{"record":{"id":"0090975615aa7dbd","repo":"astral-sh/ruff","slug":"missing-prefix-attribute","errorCode":null,"errorMessage":"Missing #[prefix = \"...\"] attribute","messagePattern":"Missing #\\[prefix = \"\\.\\.\\.\"\\] attribute","errorType":"exception","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"crates/ruff_macros/src/rule_namespace.rs","lineNumber":82,"sourceCode":"                                    starting with the character '{c}'\"\n                                ),\n                            ));\n                        }\n                    }\n                }\n                if !all_prefixes.insert(str.clone()) {\n                    return Err(Error::new(\n                        lit.span(),\n                        \"prefix has already been defined before\",\n                    ));\n                }\n                Ok(str)\n            })\n            .collect();\n        let prefixes = prefixes?;\n\n        if prefixes.is_empty() {\n            return Err(Error::new(\n                variant.span(),\n                r#\"Missing #[prefix = \"...\"] attribute\"#,\n            ));\n        }\n\n        let Some(doc_attr) = variant\n            .attrs\n            .iter()\n            .find(|attr| attr.path().is_ident(\"doc\"))\n        else {\n            return Err(Error::new(variant.span(), \"expected a doc comment\"));\n        };\n\n        let variant_ident = variant.ident;\n\n        if variant_ident != \"Ruff\" && variant_ident != \"Numpy\" {\n            let (name, url) = parse_doc_attr(doc_attr)?;\n            name_match_arms.extend(quote! {Self::#variant_ident => #name,});","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ruff_macros/src/rule_namespace.rs#L64-L100","documentation":"This is a compile-time error from the proc macro that derives the rule namespace enum (e.g. RuleNamespace) used by Ruff linters. Every variant of the enum except special-cased ones (like `Ruff` and `Numpy`) must carry a `#[prefix = \"...\"]` attribute that maps the linter to its rule-code prefix. The macro aborts expansion when it encounters a variant with no such attribute, so the crate fails to compile.","triggerScenarios":"Adding a new variant to a linter-namespace enum (annotated with ruff_macros' rule namespace derive) without adding a `#[prefix = \"...\"]` attribute on that variant. The error is raised with the variant's span at rule_namespace.rs:82 when the collected `prefixes` vec is empty.","commonSituations":"Contributing a new linter/plugin to Ruff or ty and forgetting the prefix attribute; renaming or refactoring variants in a way that drops attributes; copy-pasting a variant declaration from a struct/enum that doesn't use this derive.","solutions":["Add a `#[prefix = \"<code-prefix>\"]` attribute to the offending enum variant, e.g. `#[prefix = \"FLY\"]`.","If the variant is not a real linter, check whether it should be special-cased in the macro (like `Ruff`/`Numpy`) or removed.","Re-run the build to confirm the macro now generates the expected namespace code."],"exampleFix":"// before\npub enum Linter {\n    #[documentation(...)]\n    MyLinter,\n}\n// after\npub enum Linter {\n    #[prefix = \"MYL\"]\n    MyLinter,\n}","handlingStrategy":"validation","validationCode":"// Before building, verify every non-special variant carries a prefix attribute:\n// grep -L 'prefix' will not work per-variant; instead rely on the derive error's span,\n// or add a unit check:\n// #[test]\n// fn variants_have_prefix() { /* assert prefix table contains each variant name */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy an existing variant block (doc comment + #[prefix]) when adding a new linter.","Add the prefix attribute in the same commit/patch as the new variant.","Keep a checklist item in the contributing guide: 'new linter variant needs #[prefix and doc link'."],"tags":["proc-macro","compile-time","rust","attribute"],"backgroundTag":"missing-macro-attribute","analyzedSha":"26f38c119cac42e4d320ba08f09224fdec74af2c","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}