neon-bindings/neon · error
Context parameters must be a `&mut` reference. Try `&mut…
Error message
Context parameters must be a `&mut` reference. Try `&mut FunctionContext` or `&mut Cx`.
What it means
A neon class method or exported function declared a context parameter by value or as a non-reference type (e.g. `FunctionContext`, `Cx`). Contexts in neon must always be passed as mutable references (`&mut FunctionContext`, `&mut Cx`) because they borrow the Node execution environment. The proc macro enforces this and fails the compilation otherwise.
Solutions
- Change the parameter to a mutable reference: `&mut FunctionContext` (for exported functions) or `&mut Cx` (for class methods).
- Add the `mut` if you already have a reference: `&FunctionContext` -> `&mut FunctionContext`.
- If the type is not meant to be a context at all, rename it / use a different type so the macro does not infer a context parameter.
- Check the `#[neon]`/`#[neon(context)]` attribute: if it forces a context parameter, the first non-self argument must satisfy the `&mut` reference requirement.
Example fix
// before
fn log_event(cx: FunctionContext, msg: String) -> JsResult<JsUndefined> { ... }
// after
fn log_event(cx: &mut FunctionContext, msg: String) -> JsResult<JsUndefined> { ... } Defensive patterns
Strategy: type-guard
Validate before calling
// Validate exported fn/method signatures before deriving:
fn validate_context_param(ty: &str) -> Result<(), String> {
if ["FunctionContext", "Cx"].iter().any(|c| ty.contains(c)) && !ty.starts_with("&mut ") {
return Err(format!("context `{}` must be `&mut {}`", ty, ty));
}
Ok(())
} Type guard
fn is_valid_context_arg(ty: &syn::Type) -> bool {
matches!(ty, syn::Type::Reference(r)
if r.mutability.is_some() && ["Cx", "FunctionContext"].iter().any(|c| type_name(&r.elem).contains(c)))
} Prevention
- Always write exported signatures as `fn(cx: &mut FunctionContext, ...)` / `fn(&self, cx: &mut Cx, ...)`
- Never take contexts by value or as `&` — neon requires `&mut`
- Run `cargo check` before committing macro-exported code
- Keep a snippet/template of valid neon method signatures in the project docs
When it happens
Trigger: Declaring a method parameter whose type is a context type (`FunctionContext`, `Cx`, `Context`, etc.) but not a `&mut` reference — e.g. `fn f(cx: FunctionContext)` or `fn f(cx: &FunctionContext)` — either explicitly or via `#[neon(context)]` on a method whose first non-self arg is not a `&mut` reference.
Common situations: Writing a Rust function signature by habit instead of copying neon's `fn(cx: &mut FunctionContext)` idiom; converting an internal helper into an exported method without adjusting the signature; upgrading from older neon versions with different context conventions.
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.
- Unexpected `Channel` in sync method. Use `&mut…
- Must be a `&mut` reference.
- Expected an owned `Channel` instead of a reference.
- Must be a `&mut` reference.
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/b7779d15b4454aaa.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/class/mod.rs:402
Some(arg) => arg,
None => return Ok(false),
};
// Extract the reference type
let ty = match &*ty.ty {
// Tried to use a borrowed Channel
syn::Type::Reference(ty) if !opts.context && is_channel_type(&ty.elem) => {
return Err(syn::Error::new(
ty.elem.span(),
"Expected `&mut Cx` instead of a `Channel` reference.",
))
}
syn::Type::Reference(ty) => ty,
// Context needs to be a reference
_ if opts.context || is_context_type(&ty.ty) => {
return Err(syn::Error::new(
ty.ty.span(),
"Context parameters must be a `&mut` reference. Try `&mut FunctionContext` or `&mut Cx`.",
))
}
// Hint that `Channel` should be swapped for `&mut Cx`
_ if is_channel_type(&ty.ty) => {
return Err(syn::Error::new(
ty.ty.span(),
"Unexpected `Channel` in sync method. Use `&mut FunctionContext` for sync methods, or `Channel` in async/task methods.",
))
}
_ => return Ok(false),
};
// Not a forced or inferred context
if !opts.context && !is_context_type(&ty.elem) {View on GitHub (pinned to 38960e4381)