{"record":{"id":"fdb2408892af7c5a","repo":"neon-bindings/neon","slug":"the-neon-main-macro-must-only-be-used-once","errorCode":null,"errorMessage":"The `neon::main` macro must only be used once","messagePattern":"The `neon::main` macro must only be used once","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/neon/src/context/internal.rs","lineNumber":65,"sourceCode":"}\n\npub trait ContextInternal<'cx>: Sized {\n    fn cx(&self) -> &Cx<'cx>;\n    fn cx_mut(&mut self) -> &mut Cx<'cx>;\n    fn env(&self) -> Env {\n        self.cx().env\n    }\n}\n\nfn default_main(mut cx: ModuleContext) -> NeonResult<()> {\n    #[cfg(all(feature = \"napi-6\", feature = \"tokio-rt-multi-thread\"))]\n    crate::executor::tokio::init(&mut cx)?;\n    crate::registered().export(&mut cx)\n}\n\nfn init(cx: ModuleContext) -> NeonResult<()> {\n    if crate::macro_internal::MAIN.len() > 1 {\n        panic!(\"The `neon::main` macro must only be used once\");\n    }\n\n    if let Some(main) = crate::macro_internal::MAIN.first() {\n        main(cx)\n    } else {\n        default_main(cx)\n    }\n}\n\n#[no_mangle]\nunsafe extern \"C\" fn napi_register_module_v1(env: *mut c_void, m: *mut c_void) -> *mut c_void {\n    let env = env.cast();\n\n    sys::setup(env);\n\n    IS_RUNNING.with(|v| {\n        *v.borrow_mut() = true;\n    });","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/neon-bindings/neon/blob/38960e4381d9ad13b551cdf2d261f609167c9bc2/crates/neon/src/context/internal.rs#L47-L83","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n#[neon::main]\nfn main_a(mut cx: ModuleContext) -> NeonResult<()> { /* ... */ Ok(()) }\n#[neon::main]\nfn main_b(mut cx: ModuleContext) -> NeonResult<()> { /* ... */ Ok(()) }\n\n// after\n#[neon::main]\nfn main(mut cx: ModuleContext) -> NeonResult<()> {\n    main_a_impl(&mut cx)?;\n    main_b_impl(&mut cx)?;\n    Ok(())\n}","handlingStrategy":"validation","validationCode":"// CI check: fail if the crate declares more than one neon::main\ngrep -rn '#\\[neon::main\\]' src/ | wc -l  # must be <= 1","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","neon","macros","module-init"],"backgroundTag":"conflicting-config-options","analyzedSha":"38960e4381d9ad13b551cdf2d261f609167c9bc2","analyzedAt":"2026-09-13T09:05:33.640Z","contentChangedAt":"2026-09-13T09:05:33.640Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}