neon-bindings/neon · error
Unexpected `Channel` in sync method. Use `&mut…
Error message
Unexpected `Channel` in sync method. Use `&mut FunctionContext` for sync methods, or `Channel` in async/task methods.
What it means
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.
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.
Example fix
// before
fn enqueue(ch: Channel, work: JsFunction) -> JsResult<JsUndefined> { ... }
// after (sync method)
fn enqueue(cx: &mut FunctionContext, work: JsFunction) -> JsResult<JsUndefined> {
let ch = cx.channel();
...
} Defensive patterns
Strategy: type-guard
Validate before calling
// Guard: Channel belongs only in async/task methods
fn validate_sync_method(sig_name: &str, is_async: bool, first_param_ty: &str) -> Result<(), String> {
if !is_async && first_param_ty == "Channel" {
return Err(format!("{}: use &mut FunctionContext for sync methods, Channel only in async/task", sig_name));
}
Ok(())
} Type guard
fn takes_owned_channel(sig: &syn::Signature) -> bool {
sig.inputs.iter().nth(1)
.and_then(|a| match a {
syn::FnArg::Typed(p) => Some(!matches!(&*p.ty, syn::Type::Reference(_)) && type_name(&p.ty).ends_with("Channel")),
_ => None,
})
.unwrap_or(false)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
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
- Expected an owned `Channel` instead of a reference.
- Expected an owned `Channel` instead of a context reference.
- Context is not available in async functions. Try a…
- Expected `&mut Cx` instead of a `Channel` reference.
- Context parameters must be a `&mut` reference. Try `&mut…
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/79b4db572d9f7cb2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/class/mod.rs:410
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) {
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."));
}
View on GitHub (pinned to 38960e4381)