{"record":{"id":"bc959bb7941bb54e","repo":"GraphiteEditor/Graphite","slug":"the-editor-commands-module-may-not-have-other-a","errorCode":null,"errorMessage":"the #[editor_commands] module may not have other attributes","messagePattern":"the #\\[editor_commands\\] module may not have other attributes","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"proc-macros/src/editor_commands.rs","lineNumber":13,"sourceCode":"use convert_case::{Case, Casing};\nuse proc_macro2::TokenStream;\nuse quote::{quote, quote_spanned};\nuse syn::spanned::Spanned;\nuse syn::{Error, FnArg, Ident, Item, ItemFn, ItemMod, ItemUse, Pat, Visibility};\n\npub fn editor_commands_impl(attr: TokenStream, module: ItemMod) -> syn::Result<TokenStream> {\n\tif !attr.is_empty() {\n\t\treturn Err(Error::new(attr.span(), \"#[editor_commands] takes no arguments\"));\n\t}\n\tfor attr in &module.attrs {\n\t\tif !attr.path().is_ident(\"doc\") {\n\t\t\treturn Err(Error::new(attr.span(), \"the #[editor_commands] module may not have other attributes\"));\n\t\t}\n\t}\n\tlet Some((_, items)) = module.content else {\n\t\treturn Err(Error::new(module.mod_token.span, \"#[editor_commands] requires a module with an inline body\"));\n\t};\n\n\tlet mut imports: Vec<ItemUse> = Vec::new();\n\tlet mut functions: Vec<ItemFn> = Vec::new();\n\tfor item in items {\n\t\tmatch item {\n\t\t\tItem::Use(import) => imports.push(import),\n\t\t\tItem::Fn(function) => functions.push(function),\n\t\t\tother => return Err(Error::new(other.span(), \"only `use` imports and command functions may appear in an #[editor_commands] module\")),\n\t\t}\n\t}\n\n\tlet mut variants = TokenStream::new();\n\tlet mut stubs = TokenStream::new();","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/proc-macros/src/editor_commands.rs#L1-L31","documentation":"After the empty-attribute check, editor_commands_impl inspects the module's own attributes and permits only doc comments (#[doc ...]). Because the macro rewrites the module when generating editor command bindings, it cannot preserve arbitrary module-level attributes and rejects them with this spanned error.","triggerScenarios":"Adding #[cfg(test)], #[allow(dead_code)], #[macro_use], or any other non-doc attribute above the #[editor_commands] module declaration.","commonSituations":"Trying to gate generated command bindings behind a feature flag; silencing lints at module level; IDE auto-inserting attributes during refactors.","solutions":["Delete or relocate the offending attribute — the error span points at it","Put cfg/allow attributes on individual items inside the module instead of the module itself","Use doc comments (/// or #[doc]) freely; they are the only allowed module-level attributes"],"exampleFix":"// before\n#[cfg(test)]\n#[editor_commands]\nmod commands { /* ... */ }\n\n// after: move the cfg to items inside the module\n#[editor_commands]\nmod commands {\n\t#[cfg(test)]\n\tuse crate::test_helpers::*;\n\t/* ... */\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep only doc comments on the #[editor_commands] module","Place cfg/allow attributes on items inside the module, never on the module itself","When a new module-level attribute seems needed, check the macro's constraints first"],"tags":["proc-macro","rust","attribute","compile-time","editor"],"backgroundTag":"macro-attribute-misuse","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}