neon-bindings/neon · error
Context is not available in async functions. Try a…
Error message
Context is not available in async functions. Try a `Channel` instead.
What it means
Neon's export macro rejects any attempt to use the execution context (`Cx`/context type) in an `async` exported function, because the JS context is not available on the async executor's thread. Instead, Neon requires a `Channel` to schedule work back on the JavaScript thread. `check_channel` fires this error when an owned (non-reference) parameter is a context type.
Solutions
- Replace the `Cx` parameter with an owned `Channel`: `async fn f(ch: Channel)`.
- Use `ch.send(...)` or clone the channel into the future to hop back to the JS thread when you need to run JS work.
- If you genuinely need the context, convert the export to a synchronous function.
Example fix
// before
#[neon::export]
async fn fetch(cx: Cx, url: String) -> JsResult<JsString> { /* ... */ }
// after
#[neon::export]
async fn fetch(ch: Channel, url: String) -> JsResult<JsString> { /* ... */ } Defensive patterns
Strategy: fallback
Validate before calling
// Reject Cx params in async exports before compiling: // prefer: async fn f(ch: Channel) — schedule JS work via ch.send() // avoid: async fn f(cx: Cx)
Prevention
- In async exported functions, only take `Channel`; send closures back to the JS thread with `channel.send`.
- Convert to a synchronous export if you truly need `&mut Cx`.
- Clone the `Channel` into spawned futures/tasks rather than borrowing anything context-like.
When it happens
Trigger: Declaring `#[neon::export] async fn f(cx: Cx)` — an owned context type parameter in an async fn, matched by `_ if is_context_type(&ty.ty)`.
Common situations: Writing async exports for the first time and copying the sync signature (`cx: &mut Cx`) while dropping the reference; trying to execute JS work directly inside a `Future` running off the main thread.
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 context reference.
- Unexpected `Channel` in sync method. Use `&mut…
- 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…
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/da2f9b942e0e7a30.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/export/function/mod.rs:279
// 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.",
)),
_ => Ok(false),
}
}
// Extract the first argument, that may be a context, of a function
fn first_arg<'a>(
opts: &meta::Meta,
sig: &'a syn::Signature,
) -> syn::Result<Option<&'a syn::PatType>> {
// Extract the first argument
let arg = match sig.inputs.first() {
Some(arg) => arg,
// If context was forced, error to let the user know the mistakeView on GitHub (pinned to 38960e4381)