{"record":{"id":"ef1504b60b44a5fe","repo":"PyO3/pyo3","slug":"missing-message-in-warn-attribute","errorCode":null,"errorMessage":"missing `message` in `warn` attribute","messagePattern":"missing `message` in `warn` attribute","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"pyo3-macros-backend/src/pyfunction.rs","lineNumber":215,"sourceCode":"            if lookahead.peek(attributes::kw::message) {\n                message = content\n                    .parse::<PyFunctionWarningMessageAttribute>()\n                    .map(Some)?;\n            } else if lookahead.peek(attributes::kw::category) {\n                category = content\n                    .parse::<PyFunctionWarningCategoryAttribute>()\n                    .map(Some)?;\n            } else {\n                return Err(lookahead.error());\n            }\n\n            if content.peek(Token![,]) {\n                content.parse::<Token![,]>()?;\n            }\n        }\n\n        Ok(PyFunctionWarningAttribute {\n            message: message.ok_or(syn::Error::new(\n                content.span(),\n                \"missing `message` in `warn` attribute\",\n            ))?,\n            category,\n            span,\n        })\n    }\n}\n\nimpl ToTokens for PyFunctionWarningAttribute {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let message_tokens = self.message.to_token_stream();\n        let category_tokens = self\n            .category\n            .as_ref()\n            .map_or(quote! {}, |cat| cat.to_token_stream());\n\n        let token_stream = quote! {","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/pyo3-macros-backend/src/pyfunction.rs#L197-L233","documentation":"The #[pyo3(warn(...))] function attribute requires a `message` string. After parsing optional category and message key-value pairs, if no `message = \"...\"` was provided the parser fails with this syn::Error, since pyo3 always needs a warning message to emit.","triggerScenarios":"Writing `#[pyo3(warn(DeprecationWarning))]` or `#[pyo3(warn)]` without `message = \"...\"` on a #[pyfunction].","commonSituations":"Developers copying only the warning category from docs/examples that show a fuller form; assuming the category alone is sufficient as with Python's warnings.warn defaults.","solutions":["Add `message = \"...\"` inside the warn attribute","Keep the category if desired: warn(category, message = \"...\")","Remove the warn attribute if no warning was intended"],"exampleFix":"// before\n#[pyo3(warn(PendingDeprecationWarning))]\n#[pyfunction]\nfn old_api() {}\n// after\n#[pyo3(warn(PendingDeprecationWarning, message = \"old_api is deprecated\"))]\n#[pyfunction]\nfn old_api() {}","handlingStrategy":"validation","validationCode":"// before compiling, verify warn attributes carry a message\nif let Some(i) = attr.find(\"warn(\") {\n    assert!(attr[i..].contains(\"message\"), \"warn needs message = \\\"...\\\"\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include message = \"...\" in #[pyo3(warn(...))]","Copy complete examples from pyo3 docs","cargo check after adding warn attributes"],"tags":["rust","pyo3","macro","attributes"],"backgroundTag":"missing-required-attribute-field","analyzedSha":"ac9b6899d348be4d54614d060dea53a645a12e36","analyzedAt":"2026-09-05T09:20:35.319Z","contentChangedAt":"2026-09-05T09:20:35.319Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}