neon-bindings/neon · error
Must be a `&mut` reference.
Error message
Must be a `&mut` reference.
What it means
This compile-time error comes from Neon's `#[neon::export]` macro when a function parameter accepts a context type (`&Cx`/`&mut Cx`-like). The macro's `check_context` validation requires that a context argument be taken by mutable reference (`&mut Cx`). An immutable reference cannot support the interior mutability that Neon's context machinery relies on, so the macro rejects the signature.
Solutions
- Change the context parameter to a mutable reference: `fn f(cx: &mut Cx)` instead of `cx: &Cx`.
- If the parameter is not actually a context type, rename/retype it so the macro does not interpret it as one.
- If the function does not need context, remove the context parameter (and any `context` attribute) entirely.
Example fix
// before
#[neon::export]
fn add1(cx: &Cx, n: f64) -> f64 { n + 1.0 }
// after
#[neon::export]
fn add1(cx: &mut Cx, n: f64) -> f64 { n + 1.0 } Defensive patterns
Strategy: validation
Validate before calling
// Compile-time guard: assert the export signature takes the context by &mut
fn assert_mut_context(cx: &mut neon::context::CxContext) {}
// use `assert_mut_context(cx);` inside the export fn; the signature itself
// (`&mut CxContext`) is validated by the macro at compile time. Type guard
fn is_mut_ref<T>(_: &mut T) -> bool { true } // prefer `&mut Cx` in every #[neon::export] signature Prevention
- Always write `&mut Cx` (never `&Cx`) for context parameters in exported functions.
- Remember the mnemonic: context = &mut reference, channel = owned value.
- Rely on `cargo check` after editing export signatures — these errors are compile-time.
When it happens
Trigger: Declaring an exported fn (or a context-marked parameter, e.g. `#[context]` or forced `context` option) whose context parameter is spelled `&Cx` or `&CxContext` instead of `&mut Cx`. Detected in `check_context` when `ty.mutability.is_none()`.
Common situations: Copy-pasting a non-export helper signature into an `#[neon::export]` fn; habitually writing `&Cx` because Rust often prefers shared references; upgrading to Neon's new export API after previously using `ModuleContext` arguments.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Expected `&mut Cx` instead of a `Channel` reference.
- Context parameters must be a `&mut` reference. Try `&mut…
- Unexpected `Channel` in sync method. Use `&mut…
- Must be a `&mut` reference.
- Expected an owned `Channel` instead of a reference.
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/f35926547c070ec2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/export/function/mod.rs:239
// Hint that `Channel` should be swapped for `&mut Cx`
_ if is_channel_type(&ty.ty) => {
return Err(syn::Error::new(
ty.ty.span(),
"Expected `&mut Cx` instead of `Channel`.",
))
}
_ => return Ok(false),
};
// Not a forced or inferred context
if !opts.context && !is_context_type(&ty.elem) {
return Ok(false);
}
// Context argument must be mutable
if ty.mutability.is_none() {
return Err(syn::Error::new(ty.span(), "Must be a `&mut` reference."));
}
// All tests passed!
Ok(true)
}
// Checks if a _async_ function has a Channel argument and if it is valid
// * If the `context` attribute is included, must be at least one argument
// * Inferred to be channel if named `Channel`
// * Channel argument must not be a reference
// * First argument must not be `FunctionContext` or `Cx`
// * Must not be a `self` receiver
fn check_channel(opts: &meta::Meta, sig: &syn::Signature) -> syn::Result<bool> {
// Extract the first argument
let ty = match first_arg(opts, sig)? {
Some(arg) => arg,
None => return Ok(false),
};View on GitHub (pinned to 38960e4381)