{"record":{"id":"19d69cea095cdda0","repo":"neon-bindings/neon","slug":"only-one-new-constructor-is-allowed-in-a-class","errorCode":null,"errorMessage":"Only one `new` constructor is allowed in a class.","messagePattern":"Only one `new` constructor is allowed in a class\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/neon-macros/src/class/mod.rs","lineNumber":790,"sourceCode":"    })\n}\n\nfn group_class_items(items: Vec<syn::ImplItem>) -> Result<ClassItems, syn::Error> {\n    let mut consts = Vec::new();\n    let mut fns = Vec::new();\n    let mut constructor = None;\n    let mut has_finalizer = false;\n\n    for item in items {\n        match item {\n            syn::ImplItem::Const(c) => consts.push(c),\n            syn::ImplItem::Fn(f) => {\n                // Check if the function is a constructor\n                if f.sig.ident == \"new\" {\n                    if constructor.is_some() {\n                        let span = syn::spanned::Spanned::span(&f);\n                        let msg = \"Only one `new` constructor is allowed in a class.\";\n                        return Err(syn::Error::new(span, msg));\n                    }\n                    constructor = Some(f);\n                    continue; // Skip adding to fns\n                } else if f.sig.ident == \"finalize\" {\n                    if has_finalizer {\n                        let span = syn::spanned::Spanned::span(&f);\n                        let msg = \"Only one `finalize` method is allowed in a class.\";\n                        return Err(syn::Error::new(span, msg));\n                    }\n                    has_finalizer = true;\n                    continue; // Skip adding to fns\n                }\n                fns.push(f)\n            }\n            _ => {\n                let span = syn::spanned::Spanned::span(&item);\n                let msg = \"`neon::class` can only contain `const` and `fn` items.\";\n                return Err(syn::Error::new(span, msg));","sourceCodeStart":772,"sourceCodeEnd":808,"githubUrl":"https://github.com/neon-bindings/neon/blob/38960e4381d9ad13b551cdf2d261f609167c9bc2/crates/neon-macros/src/class/mod.rs#L772-L808","documentation":"group_class_items in crates/neon-macros/src/class/mod.rs walks the items of a `#[impl]` class block and collects the constructor. Because a JavaScript class can only have one `new`, Neon permits at most one function named `new` per class; encountering a second one while a constructor was already recorded produces this error at the duplicate item's span.","triggerScenarios":"An `impl` block for a Neon class contains two or more methods named `new` (e.g. overloads or a private helper named `new`) — Rust has no overloading, so both are seen as constructors.","commonSituations":"Trying to emulate constructor overloading with multiple `new` fns of different parameter lists; a helper function accidentally named `new`; merge conflicts that duplicate the constructor block.","solutions":["Keep exactly one `new` constructor in the class impl","Move extra logic into private helper functions with different names and call them from the single constructor","If you need multiple construction paths, accept different argument shapes in the one constructor (e.g. an options object) or provide named static factory methods marked `#[method]`","Rename any non-constructor helper that happens to be called `new`"],"exampleFix":"// before\nimpl MyCoord {\n    #[constructor]\n    fn new(cx: &mut FunctionContext) -> JsResult<JsMyCoord> { ... }\n    #[constructor]\n    fn new_from_xy(cx: &mut FunctionContext) -> JsResult<JsMyCoord> { ... }\n}\n// after\nimpl MyCoord {\n    #[constructor]\n    fn new(cx: &mut FunctionContext) -> JsResult<JsMyCoord> { ... }\n    #[method]\n    fn from_xy(cx: &mut FunctionContext) -> JsResult<JsMyCoord> { ... }\n}","handlingStrategy":"validation","validationCode":"fn ensure_single_constructor(items: &[syn::ImplItem]) -> Result<(), String> {\n    let count = items.iter().filter(|i| matches!(i, syn::ImplItem::Fn(f) if f.sig.ident == \"new\")).count();\n    if count > 1 { Err(format!(\"{} constructors named `new` found\", count)) } else { Ok(()) }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One `new` per class; use differently named `#[method]` factories for alternate construction paths","Grep impl blocks for duplicate `fn new` before building","Avoid naming private helpers `new`; prefer `default_`, `build_` prefixes"],"tags":["rust","neon","proc-macro","constructor","duplicate"],"backgroundTag":"duplicate-constructor-definition","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"}