pydantic/monty · error · syn::Error

`kwargs_not_supported_yet` cannot be combined with `kwarg_er

Error message

`kwargs_not_supported_yet` cannot be combined with `kwarg_error_name` — the override only applies to the unknown-kwarg dispatch path, which is skipped

What it means

This is a compile-time validation error from monty's `#[derive(FromArgs)]` proc macro (in `crates/monty-macros/src/from_args.rs:275`, inside `validate`). A struct declared `kwargs_not_supported_yet` also set `kwarg_error_name`. The flag makes the binder reject every keyword argument up front, which skips the unknown-kwarg dispatch path entirely — so the custom function-name override in `kwarg_error_name` would never be used, and the macro refuses the contradictory combination instead of silently ignoring it.

Source

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

        if self.kwarg_error_name.is_some() && !matches!(self.style, Style::Def | Style::Clinic | Style::Unpack) {
            return err("`kwarg_error_name` is only meaningful with `style = def`, the default \
                 `clinic` style, or `style = unpack` (where it names the function in the \
                 `takes no keyword arguments` error) — the C families defer unknown-kwarg \
                 errors past binding");
        }

        if self.kwargs_not_supported_yet {
            if self.varkwargs_idx.is_some() {
                return err("`kwargs_not_supported_yet` cannot be combined with `varkwargs` \
                     — the flag rejects every kwarg up front, so there's nothing to collect");
            }
            if self.fields.iter().any(|f| matches!(f.kind, FieldKind::KwOnly)) {
                return err("`kwargs_not_supported_yet` cannot be combined with `kw_only` fields \
                     — the flag rejects every kwarg up front, so kw_only slots are unreachable");
            }
            if self.kwarg_error_name.is_some() {
                return err("`kwargs_not_supported_yet` cannot be combined with `kwarg_error_name` \
                     — the override only applies to the unknown-kwarg dispatch path, which is skipped");
            }
        }

        // The runtime binder's fast path fills the first `n` positional slots
        // and assumes that satisfies every required positional param — sound
        // only if required positional fields precede defaulted ones (the same
        // ordering Python enforces for `def` signatures).
        let mut seen_positional_default = false;
        for field in &self.fields {
            if !matches!(field.kind, FieldKind::PosOnly | FieldKind::PosOrKeyword) {
                continue;
            }
            if field.default.is_some() {
                seen_positional_default = true;
            } else if seen_positional_default {
                return Err(syn::Error::new(
                    field.ident.span(),

View on GitHub (pinned to adc986b362)

Solutions

  1. Remove `kwarg_error_name` — `kwargs_not_supported_yet` already rejects all kwargs; the default error message is used.
  2. Remove `kwargs_not_supported_yet` if you need the custom `takes no keyword arguments` message with the function name; keep `style = unpack` so the unknown-kwarg dispatch path runs and `kwarg_error_name` applies.
  3. Check `crates/monty-macros/README.md` for which attributes are mutually exclusive and pick the single annotation matching the CPython parser family you are modeling.

Example fix

// before
#[derive(FromArgs)]
#[from_args(name = "normalize", style = unpack, kwargs_not_supported_yet, kwarg_error_name = "normalize")]
struct NormalizeArgs {
    #[from_args(pos_only)]
    form: StrArg,
}

// after — keep the custom message, drop the eager flag
#[derive(FromArgs)]
#[from_args(name = "normalize", style = unpack, kwarg_error_name = "normalize")]
struct NormalizeArgs {
    #[from_args(pos_only)]
    form: StrArg,
}
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on both attributes, grep the derive input — the macro rejects:
// attrs contains 'kwargs_not_supported_yet' AND attrs contains 'kwarg_error_name'
const conflicting = attrs.includes('kwargs_not_supported_yet') && attrs.includes('kwarg_error_name');
if (conflicting) throw new Error('pick one: eager kwarg rejection or custom kwarg error name');

Prevention

When it happens

Trigger: Writing `#[from_args(name = "f", kwargs_not_supported_yet, kwarg_error_name = "f")]` (any `kwarg_error_name` value) on a `#[derive(FromArgs)]` struct. It is a compile error at the derive site, not a runtime failure.

Common situations: A developer porting a CPython `PyArg_UnpackTuple`-style function wants the exact `f() takes no keyword arguments` message (via `kwarg_error_name`) and also adds `kwargs_not_supported_yet` to reject kwargs eagerly, not realizing the two annotations target different code paths and cannot coexist.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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