PyO3/pyo3 · error

no class given for Fn with a "self" receiver

Error message

no class given for Fn with a "self" receiver

What it means

Inside pyo3-macros-backend's method handling, FnType::self_arg requires the class name (cls) to build the receiver conversion for methods that take `self`. The expect panics when the caller supplied None for a method type that needs a self receiver. This is an internal API contract of the macro crate, not a message users normally see.

Source

Thrown at pyo3-macros-backend/src/method.rs:281

                false
            }
        }
    }

    pub fn self_arg(
        &self,
        cls: Option<&syn::Type>,
        error_mode: ExtractErrorMode,
        self_conversion: SelfConversionPolicy,
        class_method_receiver: ClassMethodReceiver,
        holders: &mut Holders,
        ctx: &Ctx,
    ) -> Option<TokenStream> {
        let Ctx { pyo3_path, .. } = ctx;
        match self {
            FnType::Getter(st) | FnType::Setter(st) | FnType::Deleter(st) | FnType::Fn(st) => {
                Some(st.receiver(
                    cls.expect("no class given for Fn with a \"self\" receiver"),
                    error_mode,
                    self_conversion,
                    holders,
                    ctx,
                ))
            }
            FnType::FnClass(span) => {
                let py = syn::Ident::new("py", Span::call_site());
                let slf: Ident = syn::Ident::new("_slf", Span::call_site());
                let pyo3_path = pyo3_path.to_tokens_spanned(*span);
                let class_method_receiver = match class_method_receiver {
                    ClassMethodReceiver::Class => quote! { #slf.cast() },
                    ClassMethodReceiver::Instance => {
                        let type_check = match self_conversion.0 {
                            SelfConversionPolicyInner::Trusted => quote! {},
                            SelfConversionPolicyInner::Checked => {
                                let cls = cls.expect("no class given for a class method");
                                let type_check = error_mode.handle_error(

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Pass the enclosing class identifier (Some(cls)) when calling self_arg for any self-receiving method.
  2. Only call self_arg with None for FnType without a self receiver (e.g. associated/classmethod variants that don't need it).
  3. If you are not writing macro code, this indicates a pyo3 bug — report with a minimal repro.

Example fix

// before
ftype.self_arg(cls=None, ...)
// after
ftype.self_arg(Some(ident_of_class), ...)
Defensive patterns

Strategy: validation

Validate before calling

// Internal callers: assert class context before generating self receiver
assert!(cls.is_some(), "self-receiving methods require a class name");

Type guard

fn has_class_context(cls: &Option<syn::Ident>) -> bool { cls.is_some() }

Prevention

When it happens

Trigger: Calling the internal FnType::self_arg API (e.g. from a custom proc macro reusing pyo3's method codegen) with cls = None while the FnType is Getter/Setter/Deleter/Fn — i.e. any method with a self receiver.

Common situations: Custom derive/attribute macros built on pyo3 internals forgetting to thread the enclosing class name; upstream pyo3 always passes Some(cls) from #[pyclass] expansion.

Related errors


AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05). Data as JSON: /api/errors/5009ec3c452bc6a3. Report an issue: GitHub.