PyO3/pyo3 · error
Named fields should have identifiers
Error message
Named fields should have identifiers
What it means
This is an internal invariant panic in PyO3's #[pyclass]/derive proc-macro backend. When processing a struct with named fields, the macro unwraps each field's identifier via Option::expect. Syn guarantees that fields inside syn::Fields::Named always carry an identifier, so this panic indicates the macro was invoked on a malformed or mutated AST rather than anything a normal user can trigger.
Source
Thrown at pyo3-macros-backend/src/intopyobject.rs:154
);
ensure_spanned!(
options.rename_all.is_none(),
options.rename_all.span() => "`rename_all` is not permitted on `transparent` structs and variants"
);
ensure_spanned!(
attrs.into_py_with.is_none(),
attrs.into_py_with.span() => "`into_py_with` is not permitted on `transparent` structs or variants"
);
ContainerType::StructNewtype(field)
} else {
let struct_fields = named
.named
.iter()
.map(|field| {
let ident = field
.ident
.as_ref()
.expect("Named fields should have identifiers");
let attrs = FieldAttributes::from_attrs(&field.attrs)?;
Ok(NamedStructField {
ident,
field,
item: attrs.getter.and_then(|getter| match getter {
crate::derive_attributes::FieldGetter::GetItem(_, lit) => {
Some(ItemOption(lit))
}
crate::derive_attributes::FieldGetter::GetAttr(_, _) => None,
}),
into_py_with: attrs.into_py_with,
})
})
.collect::<Result<Vec<_>>>()?;
ContainerType::Struct(struct_fields)
}View on GitHub (pinned to ac9b6899d3)
Solutions
- Verify you are using an unmodified, compatible pyo3 version (pyo3 and pyo3-macros-backend from the same release).
- Check that the derive input is a normal struct with named fields (no tuple/unit struct passed where named-field handling runs).
- If you reuse pyo3 macro internals, ensure you only call this path with syn::Fields::Named input.
- File a minimal reproduction against pyo3 if the panic occurs with valid code.
Example fix
// before (struct that confuses the macro path)
#[derive(IntoPyObject)]
struct MyStruct(u32);
// after (named-field struct)
#[derive(IntoPyObject)]
struct MyStruct { value: u32 } Defensive patterns
Strategy: validation
Validate before calling
// Ensure the derive input is a named-field struct
match &input.data {
syn::Data::Struct(s) => matches!(s.fields, syn::Fields::Named(_)),
_ => false,
}; Type guard
fn is_named_field_struct(item: &syn::Item) -> bool {
matches!(&item.data, syn::Data::Struct(s) if matches!(s.fields, syn::Fields::Named(_)))
} Prevention
- Keep pyo3 and pyo3-macros-backend versions in lockstep (same crate release).
- Only apply the derive to plain named-field structs.
- Avoid forks/patches of the macro backend unless you understand its invariants.
When it happens
Trigger: Only reachable if the syn AST is corrupted or a fork/plugins passes unnamed fields where named fields are expected; not reachable from ordinary #[derive(IntoPyObject)] / #[pyclass] usage on a valid struct.
Common situations: Practically never seen by end users; may surface when pinning an unusual syn version, using a fork of pyo3-macros-backend, or writing a custom derive that reuses PyO3's internal APIs.
Related errors
- no class given for Fn with a "self" receiver
- no class given for a class method
- complex enum has a non-unit variant
- named field has an identifier
- should always have positional defaults <= positional paramet
AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05).
Data as JSON: /api/errors/887be06314c2edf4.
Report an issue: GitHub.