vectordotdev/vector · error · syn::Error

`required_one_of` requires the field to be optional; use `Op

Error message

`required_one_of` requires the field to be optional; use `Option<T>` or add `#[serde(default)]`

What it means

Compile-time error from `build_named_struct_generate_schema_fn`. A field in a `required_one_of` group may legitimately be absent (the group only requires ONE of its members), so each member must be optional: `Option<T>`, a field-level `#[serde(default)]`, or a container-level `#[serde(default)]`. If none of those hold, a missing group member could never deserialize and the macro rejects it.

Source

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

            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(),
                    "`required_one_of` cannot be applied to a `#[serde(skip_deserializing)]` field; users cannot set its value",
                )
                .to_compile_error();
            }
        }
    }

    // Collect required_one_of groups at macro-expansion time: group_name -> [serde field names].
    let mut groups: std::collections::BTreeMap<String, Vec<String>> =
        std::collections::BTreeMap::new();

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Wrap the field in `Option<T>`: `pub b: Option<B>`
  2. Or add `#[serde(default)]` to the field so omission deserializes to Default
  3. Or add `#[serde(default)]` on the whole struct (container default) if all fields can default

Example fix

// before
#[configurable(required_one_of = ["api_key", "credentials_path"])]
pub credentials_path: PathBuf,

// after
#[configurable(required_one_of = ["api_key", "credentials_path"])]
pub credentials_path: Option<PathBuf>,
Defensive patterns

Strategy: validation

Validate before calling

# CI gate: non-optional group members fail at compile time
cargo check --workspace --all-targets

Prevention

When it happens

Trigger: `#[configurable(required_one_of = ["a", "b"])]` on a plain `pub b: B` field (not Option) in a struct with no field or container default.

Common situations: Porting hand-written `#[serde(deny_unknown_fields)]`-style validation to the new required_one_of mechanism and forgetting that group members must be individually omittable.

Related errors


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