vectordotdev/vector · error

#tag_already_contained

Error message

#tag_already_contained

What it means

This is a compile-time panic emitted by the generated schema-building code of the `Configurable` derive macro. When generating the schema for an adjacently-tagged (or similarly tagged) enum variant, the macro inserts a synthetic `tag` property into the variant's `properties` and `required` sets. If the variant's own fields already contain a property with the same name as the tag key, the insertion collides and the macro panics, because the generated JSON Schema would be self-contradictory (two definitions for one property name).

Solutions

  1. Rename the conflicting field inside the variant struct so it no longer matches the tag key
  2. Change the enum-level tag name via the tag attribute to something that does not collide with any variant field
  3. Prefix or restructure the variant's fields so the tag property is generated only by the macro

Example fix

// before
#[configurable(tag = "type")]
enum Source {
  A { type: String, port: u16 },
}
// after
#[configurable(tag = "type")]
enum Source {
  A { kind: String, port: u16 },
}
Defensive patterns

Strategy: validation

Validate before calling

// Before deriving Configurable on a tagged enum, check variant fields against the tag:
fn tag_conflicts<'a>(tag: &str, variant_fields: impl IntoIterator<Item = &'a str>) -> bool {
    variant_fields.into_iter().any(|f| f == tag)
}
// assert!(!tag_conflicts("type", ["type", "port"]), "field collides with tag key");

Prevention

When it happens

Trigger: Deriving `Configurable` on an enum annotated with an adjacent/internal tag (e.g. `#[configurable(tag = "type")]`) where one of the variant structs already declares a field whose name equals the tag key (`type`), so `properties.insert(tag)` returns `Some` or `required.insert` returns `false` during `generate_enum_variant_schema`.

Common situations: Adding a new enum variant whose struct reuses the tag field name; renaming a tag attribute to collide with an existing variant field; copying a variant definition from another enum that uses a different tag name.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/0aea08ddee58d830. Report an issue: GitHub.

Appendix: source

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

        // { "field_using_enum": { "<tag>": "VariantName", "some_field": false } }
        //
        // # Struct form with unnamed field is not valid here.  See comments below.
        //
        // # Unit form.
        // { "field_using_enum": { "<tag>": "VariantName" } }
        Tagging::Internal { tag } => match variant.style() {
            Style::Struct => {
                let tag_already_contained = format!(
                    "enum tag `{tag}` already contained as a field in variant; tag cannot overlap with any fields in any variant"
                );

                // Just generate the tag field directly and pass it along to be included in the
                // struct schema.
                let tag_schema = generate_enum_variant_tag_schema(variant);
                let tag_field = quote! {
                    {
                        if let Some(_) = properties.insert(#tag.to_string(), #tag_schema) {
                            panic!(#tag_already_contained);
                        }

                        if !required.insert(#tag.to_string()) {
                            panic!(#tag_already_contained);
                        }
                    }
                };
                generate_enum_struct_named_variant_schema(
                    variant,
                    Some(tag_field),
                    Some(tag),
                    false,
                )
            }
            Style::Tuple => panic!("tuple variants should be rejected during AST parsing"),
            Style::Newtype => {
                // We have to delegate viability to `serde`, essentially, because using internal tagging for a newtype
                // variant is only possible when the inner field is a struct or map, and we can't access that type of

View on GitHub (pinned to bdb87aeaa4)