neon-bindings/neon · error

Expected type name

Error message

Expected type name

What it means

When exporting a class with #[neon] export, the macro inspects the impl's self type and requires it to be a path to a named type whose path has at least one segment. An empty or unresolvable path segment yields this error at the self type span.

Solutions

  1. Implement on the named type directly, e.g. `impl Greet` instead of `impl &Greet`
  2. Remove references/generics wrappers from the self type so it is a simple named path
  3. Check that macro-generated self types expand to a plain identifier

Example fix

// before
#[neon]
impl &Greet { // self type is not a named path
    fn new(cx: &mut FunctionContext) -> JsResult<JsGreet> { ... }
}
// after
#[neon]
impl Greet {
    fn new(cx: &mut FunctionContext) -> JsResult<JsGreet> { ... }
}
Defensive patterns

Strategy: type-guard

Type guard

// ensure the impl self type is a simple named path
fn is_named_type(sig: &syn::ImplSignature) -> bool {
    matches!(**sig.self_ty, syn::Type::Path(ref p) if !p.path.segments.is_empty())
}

Prevention

When it happens

Trigger: Applying #[neon] on an impl whose self type resolves to a path with zero last segments (e.g. a parenthesized, tuple, reference-to-anonymous, or otherwise malformed type where segments.last() is None).

Common situations: Impl blocks with odd self types such as `impl &Greet`, `impl (Greet,)`, or types produced by complex macro expansion that are not simple named paths.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at crates/neon-macros/src/export/class.rs:86

    // Combine the class implementation with the export registration
    quote!(
        #class_tokens
        #create_fn
    )
    .into()
}

// Extract the class identifier from an impl block
fn extract_class_ident(input: &syn::ItemImpl) -> syn::Result<syn::Ident> {
    match &*input.self_ty {
        syn::Type::Path(syn::TypePath {
            path: syn::Path { segments, .. },
            ..
        }) => {
            let syn::PathSegment { ident, .. } = segments
                .last()
                .ok_or_else(|| syn::Error::new(input.self_ty.span(), "Expected type name"))?;
            Ok(ident.clone())
        }
        _ => Err(syn::Error::new(
            input.self_ty.span(),
            "Class export can only be applied to named types",
        )),
    }
}

View on GitHub (pinned to 38960e4381)