neon-bindings/neon · error

Constructor methods cannot have a `self` receiver

Error message

Constructor methods cannot have a `self` receiver

What it means

The method named `new` acts as the class constructor, mapping to JavaScript's `new Foo(...)`. Constructors run before any instance exists, so they must not take a `self` receiver; `fn new(&self)` or `fn new(self)` is rejected by the macro.

Solutions

  1. Remove the receiver entirely: declare `fn new(...args) -> JsResult<...>` (optionally with `cx: &mut FunctionContext`).
  2. If the method legitimately needs an existing instance, rename it to something other than `new` so it is treated as a regular method.

Example fix

// before
#[neon]
impl Counter {
    fn new(&self, initial: f64) -> JsResult<JsValue> { ... }
}

// after
#[neon]
impl Counter {
    fn new(mut cx: FunctionContext, initial: f64) -> JsResult<JsValue> { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

// Constructor signature lint
fn assert_constructor_has_no_receiver(fn_name: &str, params: &[&str]) -> Result<(), String> {
    if fn_name == "new" && params.first().map(|p| p.ends_with("self")).unwrap_or(false) {
        return Err("constructor `new` must not take self".into());
    }
    Ok(())
}

Prevention

When it happens

Trigger: Declaring a constructor as `fn new(&self) -> JsResult<...>`, `fn new(&mut self)`, or `fn new(self)` inside a `#[neon] impl` block.

Common situations: Writing a conventional Rust builder-style `new(&self)`; converting a normal method into a constructor by renaming it to `new` without dropping the receiver; porting code from other Rust patterns where `new` takes `&self`.

Related errors


AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13). Data as JSON: /api/errors/e82d383fb5075f35. Report an issue: GitHub.

Appendix: source

Thrown at crates/neon-macros/src/class/mod.rs:590

            let method_type = if matches!(meta.kind, meta::Kind::AsyncFn) {
                "Async functions"
            } else {
                "Task methods"
            };
            return Err(syn::Error::new(
                sig.span(),
                format!(
                    "{} in classes must take `self` as their first parameter.",
                    method_type
                ),
            ));
        }
    }

    // Check for self parameter in constructor
    if sig.ident == "new" {
        if let Some(syn::FnArg::Receiver(_)) = sig.inputs.first() {
            return Err(syn::Error::new(
                sig.ident.span(),
                "Constructor methods cannot have a `self` receiver",
            ));
        }
    } else {
        fn starts_with_self_arg(sig: &syn::Signature) -> bool {
            if let Some(first_arg) = sig.inputs.first() {
                matches!(first_arg, syn::FnArg::Receiver(_))
            } else {
                false
            }
        }

        // Check for self parameter in non-constructor methods
        if !starts_with_self_arg(sig) {
            return Err(syn::Error::new(
                sig.ident.span(),
                "Class methods must have a `self` receiver (`&self` or `&mut self`) as their first parameter",

View on GitHub (pinned to 38960e4381)