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

  1. Verify you are using an unmodified, compatible pyo3 version (pyo3 and pyo3-macros-backend from the same release).
  2. Check that the derive input is a normal struct with named fields (no tuple/unit struct passed where named-field handling runs).
  3. If you reuse pyo3 macro internals, ensure you only call this path with syn::Fields::Named input.
  4. 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

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


AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05). Data as JSON: /api/errors/887be06314c2edf4. Report an issue: GitHub.