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
- Remove the `self` receiver from the constructor signature
- Make the first parameter a context reference like `&mut FunctionContext` (or omit arguments entirely if no context is needed)
- 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
- Always write constructors as associated functions with no `self`
- Reserve `self` receivers for `#[method]` functions only
- Compile early with `cargo check` after adding `#[constructor]` to catch proc-macro diagnostics fast
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
- Unexpected second receiver argument.
- Expected a context argument. Try removing the `context`…
- Context must be a `&mut` reference.
- Only one `new` constructor is allowed in a class.
- Expected an owned `Channel` instead of a context reference.
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 referenceView on GitHub (pinned to 38960e4381)