{"record":{"id":"d56ec8f5bd7f3a2b","repo":"PyO3/pyo3","slug":"no-class-given-for-a-class-method","errorCode":null,"errorMessage":"no class given for a class method","messagePattern":"no class given for a class method","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pyo3-macros-backend/src/method.rs","lineNumber":298,"sourceCode":"                Some(st.receiver(\n                    cls.expect(\"no class given for Fn with a \\\"self\\\" receiver\"),\n                    error_mode,\n                    self_conversion,\n                    holders,\n                    ctx,\n                ))\n            }\n            FnType::FnClass(span) => {\n                let py = syn::Ident::new(\"py\", Span::call_site());\n                let slf: Ident = syn::Ident::new(\"_slf\", Span::call_site());\n                let pyo3_path = pyo3_path.to_tokens_spanned(*span);\n                let class_method_receiver = match class_method_receiver {\n                    ClassMethodReceiver::Class => quote! { #slf.cast() },\n                    ClassMethodReceiver::Instance => {\n                        let type_check = match self_conversion.0 {\n                            SelfConversionPolicyInner::Trusted => quote! {},\n                            SelfConversionPolicyInner::Checked => {\n                                let cls = cls.expect(\"no class given for a class method\");\n                                let type_check = error_mode.handle_error(\n                                    quote_spanned! { *span =>\n                                        #pyo3_path::Bound::ref_from_ptr(#py, &#slf).cast::<#cls>()\n                                    },\n                                    ctx,\n                                );\n                                quote! { #type_check; }\n                            }\n                        };\n                        quote! {{\n                            #type_check\n                            #pyo3_path::ffi::Py_TYPE(#slf).cast()\n                        }}\n                    }\n                };\n                let ret = quote_spanned! { *span =>\n                    #[allow(clippy::useless_conversion, reason = \"#[classmethod] accepts anything which implements `From<&Bound<PyType>>`\")]\n                    ::core::convert::Into::into(","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/pyo3-macros-backend/src/method.rs#L280-L316","documentation":"When generating code for a #[classmethod]-style method, PyO3 checks the `cls` (self) argument. With the default Checked self-conversion policy it must know the target class to emit a Bound::ref_from_ptr(...).cast::<Cls>() type check; the expect panics if no class was provided. Like error 72, this guards pyo3-macros-backend's internal API contract.","triggerScenarios":"Invoking the internal FnType::self_arg with cls = None for a class method whose SelfConversionPolicy is Checked (the default); i.e. class methods must always receive their class name.","commonSituations":"Hand-rolled macros or codegen tools reusing pyo3 method internals and omitting the class context; not reachable through normal #[pyclass] / #[classmethod] usage.","solutions":["Supply Some(cls) when generating a class method's self argument.","Alternatively mark the conversion as Trusted only if you can guarantee the pointer is the right type (unsafe; avoid).","Report to pyo3 if triggered by stock macros with valid code."],"exampleFix":"// before\nself_arg(None) // for a #[classmethod] with default (checked) conversion\n// after\nself_arg(Some(class_ident))","handlingStrategy":"validation","validationCode":"// Class methods with Checked conversion need cls\nif policy == Checked { assert!(cls.is_some(), \"class method requires cls\"); }","typeGuard":"fn classmethod_ok(cls: &Option<syn::Ident>, trusted: bool) -> bool {\n    trusted || cls.is_some()\n}","tryCatchPattern":null,"preventionTips":["Never generate #[classmethod] code without the class identifier.","Avoid switching to Trusted conversion just to skip the check — it removes type safety.","Test generated classmethods in CI when patching macro internals."],"tags":["pyo3","proc-macro","classmethod","internal-invariant"],"backgroundTag":"internal-invariant-panic","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"}