neon-bindings/neon · error

Exported functions cannot receive `self`.

Error message

Exported functions cannot receive `self`.

What it means

The `#[neon::export]` macro refuses Rust functions whose first parameter is a `self` receiver (e.g. `fn foo(&self)`). Exported functions become plain JavaScript-callable functions, so they have no object instance to dispatch against; the macro's `first_arg` check inspects the first argument and rejects `FnArg::Receiver`.

Solutions

  1. Remove the `self` parameter and make the exported item a free function, taking needed values as explicit arguments
  2. If exporting a method-like API, export a free constructor function and call methods internally, or use a class (impl block) export instead
  3. Move the attribute off the method and export a wrapper free function that constructs the receiver
  4. Use plain `#[napi]`-style conventions: export only free functions with JS-visible argument types

Example fix

// before
struct Counter { n: u32 }
impl Counter {
    #[neon::export]
    fn increment(&self) -> u32 { self.n + 1 }
}
// after
struct Counter { n: u32 }
#[neon::export]
fn increment(n: f64) -> f64 { n + 1.0 }
Defensive patterns

Strategy: validation

Validate before calling

function assertExportableFn(fn) { if (typeof fn !== 'function') throw new TypeError('export target must be a free function'); }

Prevention

When it happens

Trigger: Applying `#[neon::export]` (via `check_context`/`check_channel` path) to an inherent or trait method that takes `self`, `&self`, `&mut self`, or `self` as its first parameter.

Common situations: Refactoring an existing Rust struct method to be exported by just adding the attribute; writing `impl MyStruct { #[neon::export] fn create(&self) {...} }`; confusing Rust methods with the macro's supported standalone functions, consts, statics, and impl blocks.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at crates/neon-macros/src/export/function/mod.rs:311

    // Extract the first argument
    let arg = match sig.inputs.first() {
        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. Try removing the `context` attribute.",
            ))
        }

        None => return Ok(None),
    };

    // Expect a typed pattern; self receivers are not supported
    match arg {
        syn::FnArg::Typed(ty) => Ok(Some(ty)),
        syn::FnArg::Receiver(arg) => Err(syn::Error::new(
            arg.span(),
            "Exported functions cannot receive `self`.",
        )),
    }
}

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)