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
- Implement on the named type directly, e.g. `impl Greet` instead of `impl &Greet`
- Remove references/generics wrappers from the self type so it is a simple named path
- 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
- Implement on concrete named structs/enums only
- Avoid `&T`, tuples, or other non-path self types in exported impls
- Check macro-expanded self types resolve to plain identifiers
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
- Class export can only be applied to named types
- 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.
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)