vectordotdev/vector · error · syn::Error

`required_one_of` cannot be applied to a `#[serde(flatten)]`

Error message

`required_one_of` cannot be applied to a `#[serde(flatten)]` field

What it means

Compile-time error from `build_named_struct_generate_schema_fn`. A `#[serde(flatten)]` field is merged into the parent object at deserialization time, so it has no top-level key of its own; a `oneOf` requirement keyed on the flattened field's name could never match. The macro rejects the combination up front.

Source

Thrown at lib/vector-config-macros/src/configurable.rs:377

}

fn build_named_struct_generate_schema_fn(
    container: &Container<'_>,
    fields: &[Field<'_>],
) -> proc_macro2::TokenStream {
    // Validate required_one_of usage before building groups.
    // Scan ALL fields (including non-visible) so #[serde(skip)] fields are caught too.
    for field in fields.iter() {
        if field.required_one_of().is_some() {
            if !field.visible() {
                return syn::Error::new(
                    field.span(),
                    "`required_one_of` cannot be applied to a `#[serde(skip)]` field",
                )
                .to_compile_error();
            }
            if field.flatten() {
                return syn::Error::new(
                    field.span(),
                    "`required_one_of` cannot be applied to a `#[serde(flatten)]` field",
                )
                .to_compile_error();
            }
            if !is_option_type(field.ty())
                && field.default_value().is_none()
                && container.default_value().is_none()
            {
                return syn::Error::new(
                    field.span(),
                    "`required_one_of` requires the field to be optional; use `Option<T>` or add `#[serde(default)]`",
                )
                .to_compile_error();
            }
            if field.skip_deserializing() {
                return syn::Error::new(
                    field.span(),

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Move `required_one_of` to the concrete, non-flattened fields that actually represent the alternatives
  2. Or stop flattening that field so it appears as a named key and can participate in the group
  3. If the flattened inner type itself needs the constraint, put required_one_of on the inner struct's own fields

Example fix

// before
#[configurable(required_one_of = ["tls"])]
#[serde(flatten)]
pub tls: TlsConfig,

// after
// put the group on the real alternative fields instead
pub tls_enabled: Option<bool>,
pub tls_files: Option<TlsFiles>,
Defensive patterns

Strategy: validation

Validate before calling

# CI gate: flatten conflicts fail at compile time
cargo check --workspace --all-targets

Prevention

When it happens

Trigger: Applying `#[configurable(required_one_of(...))]` to a field that also carries `#[serde(flatten)]` in a Configurable-derived named struct.

Common situations: Config structs that flatten a shared sub-config (e.g. a common TLS or proxy block) and then try to include the flattened field in a required-one-of group during schema work.

Related errors


AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20). Data as JSON: /api/errors/fbff8eac86908f1c. Report an issue: GitHub.