neon-bindings/neon · error

`neon::class` can only contain `const` and `fn` items.

Error message

`neon::class` can only contain `const` and `fn` items.

What it means

Items inside a `#[neon] impl` block processed by the class macro must be either `const` items or `fn` items. Any other item kind (type aliases, associated types, macros, use statements, etc.) causes this error pointing at that item.

Solutions

  1. Move the offending item (type alias, use, etc.) outside the #[neon] impl block into the module scope
  2. Convert helper code into a plain `fn` if it was meant to be a method
  3. Remove the item if it is not needed for the exported class

Example fix

// before
#[neon]
impl Greet {
    type Alias = String; // not allowed
    fn new(cx: &mut FunctionContext) -> JsResult<JsGreet> { ... }
}
// after
type Alias = String; // moved to module scope
#[neon]
impl Greet {
    fn new(cx: &mut FunctionContext) -> JsResult<JsGreet> { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

// keep the #[neon] impl block limited to fn/const items
const ALLOWED: fn(&str) -> bool = |item| {
    let t = item.trim();
    t.starts_with("fn ") || t.starts_with("const ")
};

Prevention

When it happens

Trigger: Placing a `type` alias, `use` statement, macro invocation, or other non-fn/non-const associated item inside a `#[neon]`-annotated impl block grouped by group_class_items.

Common situations: Pasting an associated type into the exported impl block; adding a helper `use` inside the impl; procedural macro items or trait associated types written directly into the class impl block.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13). Data as JSON: /api/errors/10002a85551840c3. Report an issue: GitHub.

Appendix: source

Thrown at crates/neon-macros/src/class/mod.rs:808

                        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,
        has_finalizer,
    })
}

pub(crate) fn class(
    _attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    class_with_name(_attr, item, None)
}

View on GitHub (pinned to 38960e4381)