{"record":{"id":"437fdf75d629633b","repo":"pydantic/monty","slug":"positional-only-fields-must-come-before-positional-or","errorCode":null,"errorMessage":"positional-only fields must come before positional-or-keyword, varargs, and keyword-only fields","messagePattern":"positional-only fields must come before positional-or-keyword, varargs, and keyword-only fields","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"crates/monty-macros/src/from_args.rs","lineNumber":564,"sourceCode":"    let mut varkwargs_idx = None;\n    let mut seen_varargs = false;\n    let mut seen_varkwargs = false;\n    let mut seen_pos_or_kw = false;\n    let mut seen_kw_only = false;\n    let mut pos_counter: usize = 0;\n    let mut slot_counter: usize = 0;\n    for (idx, field) in fields.iter_mut().enumerate() {\n        if seen_varkwargs {\n            return Err(syn::Error::new(\n                field.ident.span(),\n                \"no fields may appear after a `#[from_args(varkwargs)]` field\",\n            ));\n        }\n\n        match field.kind {\n            FieldKind::PosOnly => {\n                if seen_pos_or_kw || seen_kw_only || seen_varargs {\n                    return Err(syn::Error::new(\n                        field.ident.span(),\n                        \"positional-only fields must come before positional-or-keyword, varargs, and keyword-only fields\",\n                    ));\n                }\n            }\n            FieldKind::PosOrKeyword => {\n                if seen_varargs {\n                    // Implicit kw_only after varargs.\n                    field.kind = FieldKind::KwOnly;\n                    seen_kw_only = true;\n                } else if seen_kw_only {\n                    return Err(syn::Error::new(\n                        field.ident.span(),\n                        \"positional-or-keyword fields cannot appear after keyword-only fields\",\n                    ));\n                } else {\n                    seen_pos_or_kw = true;\n                }","sourceCodeStart":546,"sourceCodeEnd":582,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-macros/src/from_args.rs#L546-L582","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Move the `#[from_args(pos_only)]` field to the top of the struct, before all positional-or-keyword, varargs, and keyword-only fields","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","If the field was intended to be keyword-only, change the attribute to `#[from_args(kw_only)]` and keep it after the positional fields"],"exampleFix":"// before\n#[derive(FromArgs)]\n#[from_args(name = \"f\"])\nstruct FArgs {\n    x: i64,\n    #[from_args(pos_only)]\n    a: i64,\n}\n\n// after\n#[derive(FromArgs)]\n#[from_args(name = \"f\"])\nstruct FArgs {\n    #[from_args(pos_only)]\n    a: i64,\n    x: i64,\n}","handlingStrategy":"validation","validationCode":"// Before compiling, check field order: all #[from_args(pos_only)] fields\n// must be the first fields of the struct.\nstruct Fields<'a> { kinds: &'a [FieldKind] }\nfn pos_only_first(kinds: &[&str]) -> bool {\n    let after_non_pos_only = kinds.iter().position(|k| *k != \"pos_only\");\n    match after_non_pos_only {\n        Some(i) => !kinds[i..].contains(&\"pos_only\"),\n        None => true,\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare pos_only fields at the top of every arg struct","Mirror the target CPython function's parameter order when writing the struct","Run cargo check after each field reorder"],"tags":["rust","derive-macro","compile-time","argument-parsing"],"backgroundTag":"schema-validation-failed","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}