pydantic/monty · error · syn::Error

ToArgs can only be derived for structs with named fields or…

Error message

ToArgs can only be derived for structs with named fields or unit structs

What it means

A compile-time error from the `ToArgs` derive macro. `ToArgs` converts a Rust struct back into Python call arguments, which only makes sense for structs with named fields (or unit structs, which map to zero arguments). Tuple structs and other shapes have no named parameters to emit, so the macro rejects them.

Solutions

  1. Convert the tuple struct to named fields (e.g. `struct Args { x: i64 }`)
  2. If no fields are needed, use a unit struct `struct Args;`
  3. If the type is a tuple wrapper, drop the `ToArgs` derive and convert to arguments manually

Example fix

// before
#[derive(ToArgs)]
struct PointArgs(i64, i64);

// after
#[derive(ToArgs)]
struct PointArgs {
    x: i64,
    y: i64,
}
Defensive patterns

Strategy: validation

Validate before calling

// Only named-field or unit structs support ToArgs.
enum Shape { Named, Unit, Tuple }
fn to_args_supported(shape: Shape) -> bool {
    matches!(shape, Shape::Named | Shape::Unit)
}

Prevention

When it happens

Trigger: Deriving `ToArgs` on a tuple struct (e.g. `struct Args(i64, String)`) or any non-struct data shape accepted by the derive input position.

Common situations: Reusing an existing tuple struct for argument passing, or deriving both `FromArgs` and `ToArgs` on a struct that was recently reshaped into tuple form.

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 pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/1ea4e4e3658d5ba8. Report an issue: GitHub.

Appendix: source

Thrown at crates/monty-macros/src/to_args.rs:37

pub(crate) fn expand(input: &DeriveInput) -> syn::Result<TokenStream> {
    let DeriveInput {
        ident: struct_ident,
        data,
        ..
    } = input;

    // Unit structs yield an empty vec → trivial impl.
    let named_fields: Vec<&syn::Field> = match data {
        Data::Struct(DataStruct {
            fields: Fields::Named(named),
            ..
        }) => named.named.iter().collect(),
        Data::Struct(DataStruct {
            fields: Fields::Unit, ..
        }) => Vec::new(),
        _ => {
            return Err(syn::Error::new(
                input.span(),
                "ToArgs can only be derived for structs with named fields or unit structs",
            ));
        }
    };

    let mut proj_fields: Vec<ProjField> = Vec::with_capacity(named_fields.len());
    let mut seen_varargs = false;
    for field in named_fields {
        let attrs = parse_field_attrs(&field.attrs)?;
        let ident = field.ident.clone().expect("named field");
        // Mirror FromArgs' "implicit kw_only after varargs" rule.
        let mut kind = attrs.kind;
        match kind {
            FieldKind::Varargs => seen_varargs = true,
            FieldKind::PosOrKeyword if seen_varargs => kind = FieldKind::KwOnly,
            _ => {}
        }

View on GitHub (pinned to adc986b362)