{"record":{"id":"fbe29f63f26cee11","repo":"risingwavelabs/risingwave","slug":"variant-object-cannot-have-duplicate-field-name","errorCode":null,"errorMessage":"variant object cannot have duplicate field name `{field_name}`","messagePattern":"variant object cannot have duplicate field name `(.+?)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/src/types/variant.rs","lineNumber":728,"sourceCode":"                })\n                .sorted_by(|a, b| a.0.cmp(&b.0))\n                .collect_vec();\n            for (field, value) in entries {\n                let mut field_builder = ObjectFieldBuilder::new(field.as_str(), &mut object);\n                append_datum_value(value, map_type.value(), &mut field_builder)?;\n            }\n            object.finish();\n        }\n        (value, ty) => bail!(\"cannot convert {} as {ty} to variant\", value.get_ident()),\n    }\n    Ok(())\n}\n\n/// Variant objects require unique field names, but RisingWave struct types allow duplicates.\n/// Callers iterate fields in name order, so comparing against the previous name suffices.\nfn reject_duplicate_field(previous: Option<&str>, field_name: &str) -> anyhow::Result<()> {\n    if previous == Some(field_name) {\n        bail!(\"variant object cannot have duplicate field name `{field_name}`\");\n    }\n    Ok(())\n}\n\nfn append_struct(\n    value: super::StructRef<'_>,\n    struct_type: &StructType,\n    builder: &mut impl VariantBuilderExt,\n) -> anyhow::Result<()> {\n    let mut object = builder\n        .try_new_object()\n        .context(\"failed to create variant struct object\")?;\n    let fields = value\n        .iter_fields_ref()\n        .zip_eq_fast(struct_type.iter())\n        .sorted_by(|(_, (field_a, _)), (_, (field_b, _))| field_a.cmp(field_b));\n    let mut previous_field_name = None;\n    for (value, (field_name, field_type)) in fields {","sourceCodeStart":710,"sourceCodeEnd":746,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/common/src/types/variant.rs#L710-L746","documentation":"Variant objects (like JSON objects) require unique field names, but RisingWave struct types may contain duplicate field names. reject_duplicate_field compares each field name against the previous one (fields are iterated in name order) and bails when a consecutive duplicate is found.","triggerScenarios":"Converting a RisingWave struct (or map) with duplicate field names to a Variant via append_struct / append_variant_value, e.g. `struct<a int,a varchar>`.","commonSituations":"Tables created with duplicate column names in nested structs (allowed in RW), then read/exported as JSON or Variant; JSON export jobs hitting this on legacy schemas.","solutions":["Rename one of the duplicate fields in the struct definition","Deduplicate fields before conversion (drop or merge same-name fields)","Change the struct definition so field names are unique"],"exampleFix":"// before\nstruct<a int,a varchar>  // duplicate 'a'\n// after\nstruct<a int,a_str varchar>","handlingStrategy":"validation","validationCode":"fn struct_fields_unique(ty: &StructType) -> bool {\n    let mut names: Vec<_> = ty.names().collect();\n    names.sort();\n    names.windows(2).all(|w| w[0] != w[1])\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = append_struct(value, ty, &mut builder) {\n    if e.to_string().contains(\"duplicate field name\") {\n        // rename fields or skip object export for this type\n    } else { return Err(e); }\n}","preventionTips":["Enforce unique field names in struct definitions at schema creation time","Rename duplicate columns before JSON/Variant export","Add schema linting that rejects duplicate nested field names"],"tags":["rust","variant","struct","duplicate-fields"],"backgroundTag":"schema-validation-failed","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}