neon-bindings/neon · error
Only one `finalize` method is allowed in a class.
Error message
Only one `finalize` method is allowed in a class.
What it means
The neon #[class] macro detects duplicate `finalize` methods when grouping class items. `finalize` implements Drop for the exported class, so at most one can exist; a second triggers this compile-time error at the span of the offending method.
Solutions
- Delete or rename one of the duplicate `finalize` methods so only one remains per class
- Merge the body of the two finalize methods into a single implementation
- If the second method is unrelated logic, rename it (e.g. `cleanup`) so the macro no longer treats it as a finalizer
Example fix
// before
impl_finalize!(Greet);
impl Class for Greet {
fn finalize<'a>(&mut self, cx: &'a mut TaskContext<'a>) {}
fn finalize<'a>(&mut self, cx: &'a mut TaskContext<'a>) {} // duplicate
}
// after
impl Class for Greet {
fn finalize<'a>(&mut self, cx: &'a mut TaskContext<'a>) {
// single merged finalizer body
}
} Defensive patterns
Strategy: validation
Validate before calling
// before compiling, ensure a single finalize per class impl
fn validate_single_finalize(items: &[&str]) -> Result<(), String> {
let count = items.iter().filter(|i| i.trim().starts_with("fn finalize")).count();
if count > 1 { Err(format!("{count} finalize methods found; only one allowed")) } else { Ok(()) }
} Prevention
- Keep at most one `finalize` method per exported class
- Search the impl block for `fn finalize` before adding a new one
- Merge cleanup logic into the existing finalizer instead of adding another
When it happens
Trigger: Declaring two `fn finalize(self)` (or similar finalizer-named) methods inside a single `#[neon] impl` block of a class annotated with #[class].
Common situations: Refactoring that leaves an old finalizer in place while adding a new one; merge conflicts that keep both variants; copy-pasting a finalize method between impl blocks without removing the original; an associated fn accidentally named `finalize`.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Expected an owned `Channel` instead of a context reference.
- Context is not available in async functions. Try a…
- Expected a context argument after `&self` when using…
- Unexpected second receiver argument.
- Cannot combine `async fn` with `#[neon(async)]` attribute
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/8274b0d736b474a4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon-macros/src/class/mod.rs:798
for item in items {
match item {
syn::ImplItem::Const(c) => consts.push(c),
syn::ImplItem::Fn(f) => {
// Check if the function is a constructor
if f.sig.ident == "new" {
if constructor.is_some() {
let span = syn::spanned::Spanned::span(&f);
let msg = "Only one `new` constructor is allowed in a class.";
return Err(syn::Error::new(span, msg));
}
constructor = Some(f);
continue; // Skip adding to fns
} else if f.sig.ident == "finalize" {
if has_finalizer {
let span = syn::spanned::Spanned::span(&f);
let msg = "Only one `finalize` method is allowed in a class.";
return Err(syn::Error::new(span, msg));
}
has_finalizer = true;
continue; // Skip adding to fns
}
fns.push(f)
}
_ => {
let span = syn::spanned::Spanned::span(&item);
let msg = "`neon::class` can only contain `const` and `fn` items.";
return Err(syn::Error::new(span, msg));
}
}
}
Ok(ClassItems {
consts,
fns,
constructor,View on GitHub (pinned to 38960e4381)