{"record":{"id":"9606dd203266991c","repo":"neon-bindings/neon","slug":"context-must-be-a-mut-reference","errorCode":null,"errorMessage":"Context must be a `&mut` reference.","messagePattern":"Context must be a `&mut` reference\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/neon-macros/src/class/mod.rs","lineNumber":688,"sourceCode":"                \"Constructor cannot have a `self` receiver\",\n            ))\n        }\n        None if opts.context => {\n            return Err(syn::Error::new(\n                sig.inputs.span(),\n                \"Expected a context argument. Try removing the `context` attribute.\",\n            ))\n        }\n        None => return Ok(false),\n    };\n\n    // Extract the reference type\n    let ty = match &*ty.ty {\n        syn::Type::Reference(ty) => ty,\n\n        // Context needs to be a reference\n        _ if opts.context || is_context_type(&ty.ty) => {\n            return Err(syn::Error::new(\n                ty.ty.span(),\n                \"Context must be a `&mut` reference.\",\n            ))\n        }\n\n        _ => return Ok(false),\n    };\n\n    // Not a forced or inferred context\n    if !opts.context && !is_context_type(&ty.elem) {\n        return Ok(false);\n    }\n\n    // Context argument must be mutable\n    if ty.mutability.is_none() {\n        return Err(syn::Error::new(ty.span(), \"Must be a `&mut` reference.\"));\n    }\n","sourceCodeStart":670,"sourceCodeEnd":706,"githubUrl":"https://github.com/neon-bindings/neon/blob/38960e4381d9ad13b551cdf2d261f609167c9bc2/crates/neon-macros/src/class/mod.rs#L670-L706","documentation":"check_constructor_context in crates/neon-macros/src/class/mod.rs requires the constructor's first argument to be a reference type (`syn::Type::Reference`). If the first parameter is neither a reference nor the caller opted out via `opts.context`, and the type still looks like a Neon context type (is_context_type), the macro rejects it: a context must be passed as `&mut Context`, not by value or as a smart pointer. This catches passing `FunctionContext` or `Cx` by value.","triggerScenarios":"First constructor parameter is a context type by value, e.g. `fn new(cx: FunctionContext)`, or a non-reference wrapper such as `Box<FunctionContext>`, while the `context` attribute is set or the type is detected as a context type.","commonSituations":"Forgetting the `&mut` when writing the signature from memory; upgrading Neon and copying an older by-value signature style; IDE auto-completing the type without the reference.","solutions":["Change the first parameter to a mutable reference: `cx: &mut FunctionContext` (or the crate's context alias like `&mut Cx`)","Never take a Neon context by value — contexts are always borrowed for the duration of the call"],"exampleFix":"// before\n#[constructor]\nfn new(cx: FunctionContext) -> JsResult<JsObject> { ... }\n// after\n#[constructor]\nfn new(cx: &mut FunctionContext) -> JsResult<JsObject> { ... }","handlingStrategy":"validation","validationCode":"fn ensure_context_is_ref(first_arg: Option<&syn::FnArg>) -> Result<(), String> {\n    match first_arg {\n        Some(syn::FnArg::Typed(t)) => match &*t.ty {\n            syn::Type::Reference(_) => Ok(()),\n            _ => Err(\"context must be `&mut <Context>`, not by value\".into()),\n        },\n        _ => Ok(()),\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never take Neon context types by value; always `&mut`","Copy signatures from Neon docs/examples verbatim","Let the compiler name the type via inference where possible to avoid hand-written mistakes"],"tags":["rust","neon","proc-macro","constructor","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"38960e4381d9ad13b551cdf2d261f609167c9bc2","analyzedAt":"2026-09-13T09:05:33.640Z","contentChangedAt":"2026-09-13T09:05:33.640Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}