neon-bindings/neon · error
Cannot combine async method with `#[neon(task)]` attribute
Error message
Cannot combine async method with `#[neon(task)]` attribute
What it means
The `#[neon]` macro rejects class methods declared `async` that also carry the `#[neon(task)]` attribute. An async fn is already executed on a separate task internally, so wrapping it again as an explicit task is contradictory and unsupported by the macro's code generation.
Solutions
- Remove the `#[neon(task)]` attribute and keep the method `async fn` (async methods are already spawned as tasks).
- Or keep `#[neon(task)]` and remove `async`, implementing the work synchronously in the task's `run` method.
- Ensure the method takes `self` by value, since both async and task methods require it.
Example fix
// before
#[neon]
impl Foo {
#[neon(task)]
async fn compute(&self) -> JsResult<JsNumber> { ... }
}
// after
#[neon]
impl Foo {
async fn compute(&self) -> JsResult<JsNumber> { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// Compile-time macro check; guard at code review / CI
fn assert_no_task_on_async(attrs: &[&str], is_async: bool) -> Result<(), String> {
if is_async && attrs.contains(&"task") {
return Err("remove #[neon(task)] from async methods".into());
}
Ok(())
} Prevention
- Remember: `async fn` in a #[neon] impl already implies task-based execution.
- Run `cargo check` before committing; this error surfaces immediately at macro expansion.
- When converting sync task methods to async, delete the `#[neon(task)]` attribute in the same commit.
When it happens
Trigger: Annotating a single class method with both forms: `#[neon(task)]` (or the combined `#[neon(task = ...)]`) on a method whose signature is `async fn`, e.g. `#[neon] impl Foo { #[neon(task)] async fn work(&self) -> ... }`.
Common situations: Developers migrate a sync task method to async and forget to remove `#[neon(task)]`; copy-pasting a task-based example and converting it to `async fn`; refactorings that add `async` for await-based I/O without revisiting the attribute list.
Understand the failure class
Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.
Related errors
- Cannot combine `async fn` with `#[neon(async)]` attribute
- in classes must take `self` by value, not `&self` or `&mut…
- in classes must take `self` as their first parameter.
- class must be implemented for a type name
- The `neon::main` macro must only be used once
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/a1a6f5d31bc0d1b6.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/class/mod.rs:542
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() {
if receiver.reference.is_some() {
// This is &self or &mut self, but we need self by value
let method_type = if matches!(meta.kind, meta::Kind::AsyncFn) {
"Async functions"
} else {
"Task methods"
};
let reason = if matches!(meta.kind, meta::Kind::AsyncFn) {
"This is required because async functions capture `self` in the Future, which must be `'static` for spawning."
} else {View on GitHub (pinned to 38960e4381)