pydantic/monty · error · syn::Error

positional-only fields must come before positional-or-keywor

Error message

positional-only fields must come before positional-or-keyword, varargs, and keyword-only fields

What it means

This is a compile-time error from the `FromArgs` derive macro in monty-macros. It fires when a struct field marked `#[from_args(pos_only)]` is declared after a positional-or-keyword field, a `varargs` field, or a keyword-only field. Python signatures require positional-only parameters to come first, so the derived binder rejects the struct definition rather than producing a signature Python could never express.

Source

Thrown at crates/monty-macros/src/from_args.rs:564

    let mut varkwargs_idx = None;
    let mut seen_varargs = false;
    let mut seen_varkwargs = false;
    let mut seen_pos_or_kw = false;
    let mut seen_kw_only = false;
    let mut pos_counter: usize = 0;
    let mut slot_counter: usize = 0;
    for (idx, field) in fields.iter_mut().enumerate() {
        if seen_varkwargs {
            return Err(syn::Error::new(
                field.ident.span(),
                "no fields may appear after a `#[from_args(varkwargs)]` field",
            ));
        }

        match field.kind {
            FieldKind::PosOnly => {
                if seen_pos_or_kw || seen_kw_only || seen_varargs {
                    return Err(syn::Error::new(
                        field.ident.span(),
                        "positional-only fields must come before positional-or-keyword, varargs, and keyword-only fields",
                    ));
                }
            }
            FieldKind::PosOrKeyword => {
                if seen_varargs {
                    // Implicit kw_only after varargs.
                    field.kind = FieldKind::KwOnly;
                    seen_kw_only = true;
                } else if seen_kw_only {
                    return Err(syn::Error::new(
                        field.ident.span(),
                        "positional-or-keyword fields cannot appear after keyword-only fields",
                    ));
                } else {
                    seen_pos_or_kw = true;
                }

View on GitHub (pinned to adc986b362)

Solutions

  1. Move the `#[from_args(pos_only)]` field to the top of the struct, before all positional-or-keyword, varargs, and keyword-only fields
  2. If the field does not need to be positional-only, remove the `#[from_args(pos_only)]` attribute so it becomes a normal positional-or-keyword field
  3. If the field was intended to be keyword-only, change the attribute to `#[from_args(kw_only)]` and keep it after the positional fields

Example fix

// before
#[derive(FromArgs)]
#[from_args(name = "f"])
struct FArgs {
    x: i64,
    #[from_args(pos_only)]
    a: i64,
}

// after
#[derive(FromArgs)]
#[from_args(name = "f"])
struct FArgs {
    #[from_args(pos_only)]
    a: i64,
    x: i64,
}
Defensive patterns

Strategy: validation

Validate before calling

// Before compiling, check field order: all #[from_args(pos_only)] fields
// must be the first fields of the struct.
struct Fields<'a> { kinds: &'a [FieldKind] }
fn pos_only_first(kinds: &[&str]) -> bool {
    let after_non_pos_only = kinds.iter().position(|k| *k != "pos_only");
    match after_non_pos_only {
        Some(i) => !kinds[i..].contains(&"pos_only"),
        None => true,
    }
}

Prevention

When it happens

Trigger: Deriving `FromArgs` on a struct where a field annotated with `#[from_args(pos_only)]` appears in the struct body after any plain (positional-or-keyword) field, any `#[from_args(varargs)]` field, or any `#[from_args(kw_only)]` field.

Common situations: Reordering struct fields while converting a hand-written `into_parts()` parser to `FromArgs`, or adding a new pos_only parameter to the end of an existing struct instead of the top.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/437fdf75d629633b. Report an issue: GitHub.