neon-bindings/neon · error

Unexpected second receiver argument.

Error message

Unexpected second receiver argument.

What it means

Compile-time error from Neon's `#[neon]` class macro, raised by `first_arg` when the second entry in a method's inputs (after `&self`) is another receiver (`self`-style argument, `syn::FnArg::Receiver`) rather than a normally typed parameter. Rust does not normally allow two receivers, so the macro treats this as an unexpected signature shape and fails with "Unexpected second receiver argument."

Solutions

  1. Remove the second receiver; a method can only have one `self` receiver.
  2. Replace the second receiver with a properly typed context parameter, e.g. `cx: &mut FunctionContext`.
  3. If generated by another macro or tool, fix the generator to emit a typed second argument.

Example fix

// before
fn update(&self, &mut self) -> JsResult<JsUndefined> {
    ...
}

// after
fn update(&self, cx: &mut FunctionContext) -> JsResult<JsUndefined> {
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

// A method signature may contain at most one receiver and it must be first.
fn validate_single_receiver(inputs: &[String]) -> Result<(), String> {
    if inputs.iter().skip(1).any(|t| t.contains("self")) {
        return Err("method has a second receiver argument; replace it with a typed parameter".into());
    }
    Ok(())
}

Type guard

fn second_arg_is_typed(inputs: &[String]) -> bool {
    inputs.get(1).map(|t| !t.contains("self")).unwrap_or(true)
}

Prevention

When it happens

Trigger: Declaring an exported class method with two self-like receivers, e.g. `fn foo(&self, &mut self)` or another receiver form appearing as the second input of the method signature processed by the macro.

Common situations: Hand-written or macro-generated signatures that mistakenly include a second `self`/`&mut self` parameter; typos where an intended typed parameter was written as `&mut self`; code generated by refactoring tools that duplicated the receiver.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

    // Extract the second argument (skip &self)
    let arg = match sig.inputs.iter().nth(1) {
        Some(arg) => arg,

        // If context was forced, error to let the user know the mistake
        None if opts.context => {
            return Err(syn::Error::new(
                sig.inputs.span(),
                "Expected a context argument after `&self` when using `#[neon(context)]`. Add a parameter like `cx: &mut FunctionContext` or remove the `context` attribute.",
            ))
        }

        None => return Ok(None),
    };

    // Expect a typed pattern; self receivers are not supported (but shouldn't appear here)
    match arg {
        syn::FnArg::Typed(ty) => Ok(Some(ty)),
        syn::FnArg::Receiver(arg) => Err(syn::Error::new(
            arg.span(),
            "Unexpected second receiver argument.",
        )),
    }
}

fn is_context_type(ty: &syn::Type) -> bool {
    let ident = match type_path_ident(ty) {
        Some(ident) => ident,
        None => return false,
    };

    ident == "FunctionContext" || ident == "Cx"
}

fn is_channel_type(ty: &syn::Type) -> bool {
    let ident = match type_path_ident(ty) {
        Some(ident) => ident,

View on GitHub (pinned to 38960e4381)