neon-bindings/neon · error
The `neon::main` macro must only be used once
Error message
The `neon::main` macro must only be used once
What it means
The `#[neon::main]` macro registers a custom module-init entry point in a global registry (`crate::macro_internal::MAIN`). At runtime, `init` checks the registry and panics if more than one `#[neon::main]` function was registered, because a native module can only have a single entry point.
Solutions
- Keep exactly one function annotated with `#[neon::main]`; merge the bodies of duplicates into that single function.
- Gate alternative main functions with `#[cfg(...)]` so only one is compiled per feature set.
- Delete the legacy `register_module!`/old main when migrating to `#[neon::main]`.
- Search the crate (`grep -rn 'neon::main'`) to find all annotated functions before adding a new one.
Example fix
// before
#[neon::main]
fn main_a(mut cx: ModuleContext) -> NeonResult<()> { /* ... */ Ok(()) }
#[neon::main]
fn main_b(mut cx: ModuleContext) -> NeonResult<()> { /* ... */ Ok(()) }
// after
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
main_a_impl(&mut cx)?;
main_b_impl(&mut cx)?;
Ok(())
} Defensive patterns
Strategy: validation
Validate before calling
// CI check: fail if the crate declares more than one neon::main grep -rn '#\[neon::main\]' src/ | wc -l # must be <= 1
Prevention
- Treat #[neon::main] as a singleton: one function, one place, documented at crate root
- Merge feature-specific init logic into a single main gated by cfg
- Delete legacy register_module! code when migrating
- Grep for the attribute before adding a new one
When it happens
Trigger: Annotating two different functions with `#[neon::main]` in the same crate (including transitively via a macro or an imported helper macro); copying example code that already contains a `#[neon::main]` into a crate that already defines one.
Common situations: Merging branches where both added a `#[neon::main]` handler; enabling a feature flag (e.g. `#[cfg(feature = "tokio")]` variants) that pulls in a second main; mixing `neon::main` with an older `register_module!` setup retained in the codebase.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- class must be implemented for a type name
- Cannot combine async method with `#[neon(task)]` attribute
- in classes must take `self` by value, not `&self` or `&mut…
- in classes must take `self` as their first parameter.
- Constructor methods cannot have a `self` receiver
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/fdb2408892af7c5a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon/src/context/internal.rs:65
}
pub trait ContextInternal<'cx>: Sized {
fn cx(&self) -> &Cx<'cx>;
fn cx_mut(&mut self) -> &mut Cx<'cx>;
fn env(&self) -> Env {
self.cx().env
}
}
fn default_main(mut cx: ModuleContext) -> NeonResult<()> {
#[cfg(all(feature = "napi-6", feature = "tokio-rt-multi-thread"))]
crate::executor::tokio::init(&mut cx)?;
crate::registered().export(&mut cx)
}
fn init(cx: ModuleContext) -> NeonResult<()> {
if crate::macro_internal::MAIN.len() > 1 {
panic!("The `neon::main` macro must only be used once");
}
if let Some(main) = crate::macro_internal::MAIN.first() {
main(cx)
} else {
default_main(cx)
}
}
#[no_mangle]
unsafe extern "C" fn napi_register_module_v1(env: *mut c_void, m: *mut c_void) -> *mut c_void {
let env = env.cast();
sys::setup(env);
IS_RUNNING.with(|v| {
*v.borrow_mut() = true;
});View on GitHub (pinned to 38960e4381)