neon-bindings/neon · error
Expected an owned `Channel` instead of a reference.
Error message
Expected an owned `Channel` instead of a reference.
What it means
In an async or task neon method (where `check_channel` applies), the first argument after `&self` was declared as a reference to a `Channel` (e.g. `&mut Channel`). Async/task methods must receive an owned `Channel`, because it is created from the context and moved into the spawned future/thread; a borrowed `Channel` cannot outlive the method call. The macro rejects references with this error.
Solutions
- Remove the reference and take the `Channel` by value: `Channel` instead of `&mut Channel` or `&Channel`.
- If you actually wanted the execution context, use `&mut Cx` only in sync methods — in async/task methods use an owned `Channel` and obtain context inside the closure/future as needed.
- If a reference was needed to avoid a move, clone the `Channel` (`Channel` is cheaply clonable) and pass the clone by value.
- Check the `#[neon(context)]` attribute: remove it if the method should not require a context parameter.
Example fix
// before
fn spawn_work(&self, ch: &mut Channel, data: Vec<u8>) { ... }
// after
fn spawn_work(&self, ch: Channel, data: Vec<u8>) { ... } Defensive patterns
Strategy: type-guard
Validate before calling
// Guard: async/task methods take owned Channel, never a reference
fn validate_channel_ownership(is_async: bool, first_param_ty: &str) -> Result<(), String> {
if is_async && first_param_ty.contains("Channel") && first_param_ty.starts_with('&') {
return Err("async/task methods must take owned Channel (no `&`)".into());
}
Ok(())
} Type guard
fn is_channel_ref(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(r) if type_name(&r.elem).ends_with("Channel"))),
_ => None,
})
.unwrap_or(false)
} Prevention
- In async/task methods always declare `ch: Channel` (owned, no `&`)
- Clone the Channel instead of borrowing it when ownership is inconvenient
- Do not use #[neon(context)] on async/task methods that take a Channel reference
- Run `cargo check` after converting methods between sync and async forms
When it happens
Trigger: Declaring an `#[neon]` AsyncFn/Task method whose first non-self parameter is `&Channel` or `&mut Channel`, or using `#[neon(context)]` on such a method with any reference-typed first argument.
Common situations: Adding `&` by reflex when defining method parameters; converting a sync method that took `&mut Channel` into an async/task method without dropping the reference; misunderstanding that async methods take ownership of the `Channel`.
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
- Unexpected `Channel` in sync method. Use `&mut…
- 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/15317a018b040862.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/class/mod.rs:445
}
// All tests passed!
Ok(true)
}
// Check if an async method has a Channel argument (adapted from export function)
fn check_channel(opts: &meta::Meta, sig: &syn::Signature) -> syn::Result<bool> {
// Extract the first argument (after &self)
let ty = match first_arg(opts, sig)? {
Some(arg) => arg,
None => return Ok(false),
};
// Check the type
match &*ty.ty {
// Provided `&mut Channel` instead of `Channel`
syn::Type::Reference(ty) if opts.context || is_channel_type(&ty.elem) => {
Err(syn::Error::new(
ty.span(),
"Expected an owned `Channel` instead of a reference.",
))
}
// Provided a `&mut Cx` instead of a `Channel`
syn::Type::Reference(ty) if is_context_type(&ty.elem) => Err(syn::Error::new(
ty.elem.span(),
"Expected an owned `Channel` instead of a context reference.",
)),
// Found a `Channel`
_ if opts.context || is_channel_type(&ty.ty) => Ok(true),
// Tried to use an owned `Cx`
_ if is_context_type(&ty.ty) => Err(syn::Error::new(
ty.ty.span(),
"Context is not available in async functions. Try a `Channel` instead.",View on GitHub (pinned to 38960e4381)