neon-bindings/neon · error

Constructor cannot have a `self` receiver

Error message

Constructor cannot have a `self` receiver

What it means

This compile-time error comes from Neon's `#[constructor]` macro support in crates/neon-macros/src/class/mod.rs (check_constructor_context). A constructor wrapper function must take a context argument (such as `&mut FunctionContext`) as its first parameter; a `self` receiver is not allowed because constructors are static factory functions, not methods. The macro rejects any `impl`-style `self` argument at the first position of the constructor signature.

Solutions

  1. Remove the `self` receiver from the constructor signature
  2. Make the first parameter a context reference like `&mut FunctionContext` (or omit arguments entirely if no context is needed)
  3. If the function genuinely needs `self`, it is not a constructor — use `#[method]` instead of `#[constructor]`

Example fix

// before
#[constructor]
fn new(&mut self, cx: &mut FunctionContext) -> JsResult<JsValue> { ... }
// after
#[constructor]
fn new(cx: &mut FunctionContext) -> JsResult<JsValue> { ... }
Defensive patterns

Strategy: validation

Validate before calling

fn validate_constructor_sig(sig: &syn::Signature) -> Result<(), String> {
    match sig.inputs.first() {
        Some(syn::FnArg::Receiver(_)) => Err("constructor must not take `self`".into()),
        Some(syn::FnArg::Typed(_)) | None => Ok(()),
    }
}

Prevention

When it happens

Trigger: Declaring a `#[constructor]`-annotated function (or a `new` method inside a `#[impl]` class block) whose signature starts with `self`, `&self`, `&mut self`, or `self: ...` instead of a context reference.

Common situations: Converting an existing Rust method into a JS constructor by adding `#[constructor]` without removing `&self`; copying a regular method's signature when authoring a new class; refactorings that turn an associated `new` fn into a method.

Related errors


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

Appendix: source

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

    };

    // Must be an identifier named `this`
    match elem {
        syn::Pat::Ident(ident) => ident.ident == THIS,
        _ => false,
    }
}

// Check if constructor has a context parameter using same heuristic as export functions
// * If the `context` attribute is included, must have at least one argument
// * Inferred to be context if first arg is `&mut FunctionContext` or `&mut Cx`
// * Context argument must be a `&mut` reference
fn check_constructor_context(opts: &meta::Meta, sig: &syn::Signature) -> syn::Result<bool> {
    // Extract the first argument
    let ty = match sig.inputs.first() {
        Some(syn::FnArg::Typed(ty)) => ty,
        Some(syn::FnArg::Receiver(_)) => {
            return Err(syn::Error::new(
                sig.inputs.span(),
                "Constructor cannot have a `self` receiver",
            ))
        }
        None if opts.context => {
            return Err(syn::Error::new(
                sig.inputs.span(),
                "Expected a context argument. Try removing the `context` attribute.",
            ))
        }
        None => return Ok(false),
    };

    // Extract the reference type
    let ty = match &*ty.ty {
        syn::Type::Reference(ty) => ty,

        // Context needs to be a reference

View on GitHub (pinned to 38960e4381)