{"record":{"id":"79b4db572d9f7cb2","repo":"neon-bindings/neon","slug":"unexpected-channel-in-sync-method-use-mut-functioncontext","errorCode":null,"errorMessage":"Unexpected `Channel` in sync method. Use `&mut FunctionContext` for sync methods, or `Channel` in async/task methods.","messagePattern":"Unexpected `Channel` in sync method\\. Use `&mut FunctionContext` for sync methods, or `Channel` in async/task methods\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/neon-macros/src/class/mod.rs","lineNumber":410,"sourceCode":"            return Err(syn::Error::new(\n                ty.elem.span(),\n                \"Expected `&mut Cx` instead of a `Channel` reference.\",\n            ))\n        }\n\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 parameters must be a `&mut` reference. Try `&mut FunctionContext` or `&mut Cx`.\",\n            ))\n        }\n\n        // Hint that `Channel` should be swapped for `&mut Cx`\n        _ if is_channel_type(&ty.ty) => {\n            return Err(syn::Error::new(\n                ty.ty.span(),\n                \"Unexpected `Channel` in sync method. Use `&mut FunctionContext` for sync methods, or `Channel` in async/task methods.\",\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":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/neon-bindings/neon/blob/38960e4381d9ad13b551cdf2d261f609167c9bc2/crates/neon-macros/src/class/mod.rs#L392-L428","documentation":"A sync neon class method declared an owned `Channel` as its first argument (after `&self`). `Channel` is not a valid sync-method parameter: sync methods take `&mut FunctionContext` (or `&mut Cx`), while `Channel` (owned) is only allowed in async/task methods. The macro emits this targeted hint instead of a generic type error.","triggerScenarios":"Declaring a Normal (sync) class method whose first non-self parameter is an owned `Channel` (e.g. `fn f(ch: Channel, ...)`), where the parameter is not a context and the method is not an async/task method.","commonSituations":"Writing an async-style method signature in a sync method; copying a `Channel`-taking callback/helper into a `#[neon]` sync method; restructuring an async method to be sync without removing the `Channel` parameter.","solutions":["For a sync method, replace `Channel` with `&mut FunctionContext` (or `&mut Cx`).","If you need the `Channel` (e.g. to schedule from another thread), make the method an async or task method and keep the owned `Channel` parameter.","Remove the `Channel` parameter if it is unused — sync methods cannot receive one.","Obtain a `Channel` inside the method instead: `let ch = cx.channel();` when you need to schedule work."],"exampleFix":"// before\nfn enqueue(ch: Channel, work: JsFunction) -> JsResult<JsUndefined> { ... }\n\n// after (sync method)\nfn enqueue(cx: &mut FunctionContext, work: JsFunction) -> JsResult<JsUndefined> {\n    let ch = cx.channel();\n    ...\n}","handlingStrategy":"type-guard","validationCode":"// Guard: Channel belongs only in async/task methods\nfn validate_sync_method(sig_name: &str, is_async: bool, first_param_ty: &str) -> Result<(), String> {\n    if !is_async && first_param_ty == \"Channel\" {\n        return Err(format!(\"{}: use &mut FunctionContext for sync methods, Channel only in async/task\", sig_name));\n    }\n    Ok(())\n}","typeGuard":"fn takes_owned_channel(sig: &syn::Signature) -> bool {\n    sig.inputs.iter().nth(1)\n        .and_then(|a| match a {\n            syn::FnArg::Typed(p) => Some(!matches!(&*p.ty, syn::Type::Reference(_)) && type_name(&p.ty).ends_with(\"Channel\")),\n            _ => None,\n        })\n        .unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Decide sync vs async before writing the signature; Channel is async/task-only","Get a Channel inside sync methods via `cx.channel()` instead of taking it as a parameter","Avoid copy-pasting async method signatures into sync methods","Run `cargo check` frequently during refactors"],"tags":["rust","neon","compile-time","macro","async"],"backgroundTag":"unsupported-operation","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"}