{"record":{"id":"dad1c1bb29c41104","repo":"vectordotdev/vector","slug":"tuple-variants-should-be-rejected-during-ast-parsing","errorCode":null,"errorMessage":"tuple variants should be rejected during AST parsing","messagePattern":"tuple variants should be rejected during AST parsing","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/vector-config-macros/src/configurable.rs","lineNumber":1144,"sourceCode":"                let tag_field = quote! {\n                    {\n                        if let Some(_) = properties.insert(#tag.to_string(), #tag_schema) {\n                            panic!(#tag_already_contained);\n                        }\n\n                        if !required.insert(#tag.to_string()) {\n                            panic!(#tag_already_contained);\n                        }\n                    }\n                };\n                generate_enum_struct_named_variant_schema(\n                    variant,\n                    Some(tag_field),\n                    Some(tag),\n                    false,\n                )\n            }\n            Style::Tuple => panic!(\"tuple variants should be rejected during AST parsing\"),\n            Style::Newtype => {\n                // We have to delegate viability to `serde`, essentially, because using internal tagging for a newtype\n                // variant is only possible when the inner field is a struct or map, and we can't access that type of\n                // information here, which is why `serde` does it at compile-time.\n\n                // As such, we generate the schema for the single field, like we would normally do for a newtype\n                // variant, and then we follow the struct flattening logic where we layer on our tag field schema on the\n                // schema of the wrapped field... and since it has to be a struct or map to be valid for `serde`, that\n                // means it will also be an object schema in both cases, which means our flattening logic will be\n                // correct if the caller is doing The Right Thing (tm).\n                let newtype_schema = generate_enum_newtype_struct_variant_schema(variant, false);\n                let tag_schema = generate_enum_variant_tag_schema(variant);\n\n                quote! {\n                    let tag_schema = ::vector_config::schema::generate_internal_tagged_variant_schema(#tag.to_string(), #tag_schema);\n                    let mut flattened_subschemas = ::std::vec::Vec::new();\n                    flattened_subschemas.push(tag_schema);\n","sourceCodeStart":1126,"sourceCodeEnd":1162,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/lib/vector-config-macros/src/configurable.rs#L1126-L1162","documentation":"The `Configurable` derive macro rejects tuple-style enum variants when generating schemas for tagged enums. Tuple variants are expected to have been detected and rejected earlier, during AST parsing of the derive input, so encountering `Style::Tuple` at schema-generation time (`generate_enum_variant_schema`) means the parser invariant was broken. The panic is a defensive assertion, not a user-fixable configuration issue at this stage.","triggerScenarios":"Schema generation reaches `Style::Tuple` in `generate_enum_variant_schema` (lib/vector-config-macros/src/configurable.rs:1144) — i.e. an enum like `enum E { V(String) }` used in a context that requires a tagged/adjacently-tagged schema, and AST parsing failed to reject it first.","commonSituations":"Declaring a newtype/tuple variant such as `Variant(Vec<u8>)` or `Variant(InnerStruct)` on an internally-tagged enum; refactoring a struct variant into a tuple variant while keeping the tag attribute.","solutions":["Convert the tuple variant to a struct variant with named fields","Wrap the payload in a struct so the variant becomes a struct/newtype variant that supports internal tagging","Remove the tag-based representation requirement (e.g. use a different enum representation) if tuple variants are required"],"exampleFix":"// before\n#[configurable(tag = \"type\")]\nenum E { Name(String) }\n// after\n#[configurable(tag = \"type\")]\nenum E { Name { value: String } }","handlingStrategy":"validation","validationCode":"// Reject tuple variants in tagged enums before compiling:\nfn has_tuple_variants(enum_name: &str, variant_styles: &[&str]) -> bool {\n    debug_assert!(\n        !variant_styles.iter().any(|s| *s == \"tuple\"),\n        \"enum {} uses tuple variants, unsupported for tagged Configurable enums\",\n        enum_name\n    );\n    variant_styles.iter().any(|s| *s == \"tuple\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only use struct, newtype-wrapping-struct, or unit variants in tagged enums","Fix AST-parse warnings about tuple variants immediately instead of working around them","Document the restriction near the enum definition"],"tags":["rust","proc-macro","enum","compile-time-panic"],"backgroundTag":"unsupported-enum-value","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}