astral-sh/ruff · error · syn::Error

Missing #[prefix = "..."] attribute

Error message

Missing #[prefix = "..."] attribute

What it means

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.

Source

Thrown at crates/ruff_macros/src/rule_namespace.rs:82

                                    starting with the character '{c}'"
                                ),
                            ));
                        }
                    }
                }
                if !all_prefixes.insert(str.clone()) {
                    return Err(Error::new(
                        lit.span(),
                        "prefix has already been defined before",
                    ));
                }
                Ok(str)
            })
            .collect();
        let prefixes = prefixes?;

        if prefixes.is_empty() {
            return Err(Error::new(
                variant.span(),
                r#"Missing #[prefix = "..."] attribute"#,
            ));
        }

        let Some(doc_attr) = variant
            .attrs
            .iter()
            .find(|attr| attr.path().is_ident("doc"))
        else {
            return Err(Error::new(variant.span(), "expected a doc comment"));
        };

        let variant_ident = variant.ident;

        if variant_ident != "Ruff" && variant_ident != "Numpy" {
            let (name, url) = parse_doc_attr(doc_attr)?;
            name_match_arms.extend(quote! {Self::#variant_ident => #name,});

View on GitHub (pinned to 26f38c119c)

Solutions

  1. Add a `#[prefix = "<code-prefix>"]` attribute to the offending enum variant, e.g. `#[prefix = "FLY"]`.
  2. If the variant is not a real linter, check whether it should be special-cased in the macro (like `Ruff`/`Numpy`) or removed.
  3. Re-run the build to confirm the macro now generates the expected namespace code.

Example fix

// before
pub enum Linter {
    #[documentation(...)]
    MyLinter,
}
// after
pub enum Linter {
    #[prefix = "MYL"]
    MyLinter,
}
Defensive patterns

Strategy: validation

Validate before calling

// Before building, verify every non-special variant carries a prefix attribute:
// grep -L 'prefix' will not work per-variant; instead rely on the derive error's span,
// or add a unit check:
// #[test]
// fn variants_have_prefix() { /* assert prefix table contains each variant name */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05). Data as JSON: /api/errors/0090975615aa7dbd. Report an issue: GitHub.