vectordotdev/vector · error · syn::Error

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

Error message

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

What it means

Compile-time error from `build_named_struct_generate_schema_fn` in vector-config-macros. Vector's `required_one_of` helper generates a schema-level `oneOf` requirement over serde field names, so every participating field must appear in the serialized/deserialized object. `#[serde(skip)]` removes the field from both, making the requirement unsatisfiable; the macro scans ALL fields (even non-visible ones) specifically to catch this.

Source

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

    quote! {
        {
            #field_schema
            subschemas.push(subschema);
        }
    }
}

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(),

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Remove the `#[configurable(required_one_of(...))]` attribute from the skipped field
  2. Or remove `#[serde(skip)]` if the field is actually user-configurable and must be part of the group
  3. Move the group membership to a visible field that carries the same semantic choice

Example fix

// before
#[configurable(required_one_of = ["strategy"])]
#[serde(skip)]
pub strategy_hint: Strategy,

// after
// (drop one of the two attributes; keep required_one_of only on deserialized fields)
pub strategy: Option<Strategy>,
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: Applying both `#[serde(skip)]` and `#[configurable(required_one_of(...))]` to the same field of a `#[derive(Configurable)]` named struct.

Common situations: Refactoring a config struct where a field became internal (skip) but its old `required_one_of` attribute was left behind; merging configs where attributes accumulated.

Related errors


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