neon-bindings/neon · error
Cannot combine `async fn` with `#[neon(async)]` attribute
Error message
Cannot combine `async fn` with `#[neon(async)]` attribute
What it means
Compile-time error from Neon's `#[neon]` class macro in `validate_method_attributes`. It fires when a method is declared `async fn` (macro kind `AsyncFn`) and is also marked with the `#[neon(async)]` attribute (kind `Async`). Both spellings request the same async treatment, so combining them is redundant and ambiguous — the macro rejects the declaration instead of guessing.
Solutions
- Remove the `#[neon(async)]` attribute and keep `async fn`.
- Alternatively, keep `#[neon(async)]` and drop the `async` keyword if the intended style is attribute-driven (verify against your Neon version's supported forms).
- Check the Neon docs for the canonical way to declare async methods in your version and use only one mechanism.
Example fix
// before
#[neon(async)]
async fn run(&self, mut cx: Channel) -> JsResult<JsUndefined> {
...
}
// after
async fn run(&self, mut cx: Channel) -> JsResult<JsUndefined> {
...
} Defensive patterns
Strategy: validation
Validate before calling
// Reject declarations that both use `async fn` and #[neon(async)].
fn validate_async_spelling(has_async_fn: bool, has_neon_async_attr: bool) -> Result<(), String> {
if has_async_fn && has_neon_async_attr {
return Err("use either `async fn` or `#[neon(async)]`, not both".into());
}
Ok(())
} Type guard
fn is_unambiguous_async(has_async_fn: bool, has_neon_async_attr: bool) -> bool {
has_async_fn ^ has_neon_async_attr
} Prevention
- Pick one async declaration style for the whole codebase (preferred: plain `async fn`) and enforce it in review.
- When converting a method to `async fn`, remove any existing `#[neon(async)]` attribute in the same edit.
- Consult the Neon docs for your pinned version to confirm which async spelling it supports.
When it happens
Trigger: Annotating a method that is already declared `async fn` with `#[neon(async)]`, e.g. `#[neon(async)] async fn run(&self, ...)`. (Note: with this macro implementation both `Kind::AsyncFn` and `Kind::Async` must be present simultaneously to trigger the error.)
Common situations: Adding `#[neon(async)]` for explicitness on an already-`async fn` method; copy-pasting attributes from a non-async method when converting it to `async fn`; mixing examples from different Neon versions that use different async spellings.
Related errors
- Expected an owned `Channel` instead of a context reference.
- Context is not available in async functions. Try a…
- Unexpected `Channel` in sync method. Use `&mut…
- Expected an owned `Channel` instead of a reference.
- Expected a context argument after `&self` when using…
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/d3dd110e2d6dfe04.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/class/mod.rs:532
ident == "Channel"
}
// Extract the identifier from the last segment of a type's path
fn type_path_ident(ty: &syn::Type) -> Option<&syn::Ident> {
let segment = match ty {
syn::Type::Path(ty) => ty.path.segments.last()?,
_ => return None,
};
Some(&segment.ident)
}
// Validate method attributes for common errors and conflicts
fn validate_method_attributes(meta: &meta::Meta, sig: &syn::Signature) -> syn::Result<()> {
// Check for conflicting async attributes
if matches!(meta.kind, meta::Kind::AsyncFn) && matches!(meta.kind, meta::Kind::Async) {
return Err(syn::Error::new(
sig.span(),
"Cannot combine `async fn` with `#[neon(async)]` attribute",
));
}
// Check for async + task conflict
if matches!(meta.kind, meta::Kind::AsyncFn | meta::Kind::Async)
&& matches!(meta.kind, meta::Kind::Task)
{
return Err(syn::Error::new(
sig.span(),
"Cannot combine async method with `#[neon(task)]` attribute",
));
}
// Validate that async fn and task methods take self by value
if matches!(meta.kind, meta::Kind::AsyncFn | meta::Kind::Task) {
if let Some(syn::FnArg::Receiver(receiver)) = sig.inputs.first() {View on GitHub (pinned to 38960e4381)