pydantic/monty · error · syn::Error
`style = def` cannot be combined with `varargs` — a `*args`
Error message
`style = def` cannot be combined with `varargs` — a `*args` signature can never raise too-many-positional, so the style has no effect
What it means
A `#[derive(FromArgs)]` struct combines `style = def` with a `*args` (varargs) field. The check rejects it because a signature accepting unlimited positionals can never produce a too-many-positional error — the whole point of the `def` style is to change that error — so the style would silently do nothing. The macro refuses no-op combinations at compile time.
Source
Thrown at crates/monty-macros/src/from_args.rs:222
signature.validate()?;
Ok(signature)
}
/// Style/modifier/field compatibility checks — the single place invalid
/// combinations are rejected. Grouped per style, then the orthogonal
/// modifiers, so each rule reads as one line of the compatibility table.
fn validate(&self) -> syn::Result<()> {
let err = |msg: &str| Err(syn::Error::new(self.struct_ident.span(), msg));
match self.style {
Style::Def => {
if self.bad_arg.is_some() {
return err("`bad_arg`/`bad_arg_named` cannot be combined with `style = def` \
— CPython `def` binding never type-checks while binding; declare \
fields as raw `Value` and coerce in the function body");
}
if self.varargs_idx.is_some() {
return err("`style = def` cannot be combined with `varargs` — a `*args` \
signature can never raise too-many-positional, so the style has no effect");
}
}
Style::Unpack => {
if self.fields.iter().any(|f| matches!(f.kind, FieldKind::PosOrKeyword)) {
return err("`style = unpack` models a positional-only `PyArg_UnpackTuple` \
signature — every positional field must be `pos_only`");
}
if self.varargs_idx.is_some() || self.varkwargs_idx.is_some() {
return err("`style = unpack` cannot be combined with `varargs` or `varkwargs` \
— it models a fixed positional min..max range");
}
}
Style::Clinic | Style::C | Style::CNamed => {}
}
if self.at_most_total {
if matches!(self.style, Style::Def | Style::Unpack) {View on GitHub (pinned to adc986b362)
Solutions
- Remove `style = "def"` — with a varargs field the default style already produces the correct behavior since too-many-positional can never occur.
- If you truly need def-binding semantics elsewhere, split the struct: a def-style one for fixed params and a separate plain struct for the variadic part.
Example fix
// before
#[derive(FromArgs)]
#[from_args(style = "def")]
struct SumArgs { #[from_args(varargs)] terms: Vec<Value> }
// after
#[derive(FromArgs)]
struct SumArgs { #[from_args(varargs)] terms: Vec<Value> } Defensive patterns
Strategy: validation
Validate before calling
// style = "def" only has an effect on fixed-arity signatures;
// skip it whenever the struct declares a varargs field.
fn should_use_def_style(has_varargs: bool) -> bool { !has_varargs } Prevention
- Only add style attributes that change observable behavior for the given signature shape.
- For variadic handlers, use the default style and rely on the runtime binder.
When it happens
Trigger: Compiling `#[derive(FromArgs)] #[from_args(style = "def")] struct Args { a: i64, #[from_args(varargs)] rest: Vec<Value> }`. Detected in `Signature::validate` when `varargs_idx.is_some()` under `Style::Def` (crates/monty-macros/src/from_args.rs:221-224).
Common situations: Writing a variadic helper (like `sum(*args)`) and picking `style = def` while copying the style attribute from a fixed-arity function; refactoring a def-style struct by adding a varargs field without revisiting the style.
Related errors
- `bad_arg`/`bad_arg_named` cannot be combined with `style = d
- `style = unpack` models a positional-only `PyArg_UnpackTuple
- `style = unpack` cannot be combined with `varargs` or `varkw
- `at_most_total` cannot be combined with `style = def` or `st
- `at_most_total` cannot be combined with `varargs` or `varkwa
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/ecf05865ed78af65.
Report an issue: GitHub.