{"record":{"id":"654721c101a11e82","repo":"databendlabs/databend","slug":"failed-to-build-jsonb-object-from-tuple","errorCode":null,"errorMessage":"failed to build jsonb object from tuple","messagePattern":"failed to build jsonb object from tuple","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/expression/src/types/variant.rs","lineNumber":377,"sourceCode":"                    let iter = fields.into_iter();\n                    let mut builder = BinaryColumnBuilder::with_capacity(iter.size_hint().0, 0);\n                    for (scalar, typ) in iter.zip(fields_type) {\n                        cast_scalar_to_variant(\n                            scalar,\n                            tz,\n                            &mut builder.data,\n                            Some(&typ.remove_nullable()),\n                        );\n                        builder.commit_row();\n                    }\n                    let values = builder.build();\n                    OwnedJsonb::build_object(\n                        values\n                            .iter()\n                            .enumerate()\n                            .map(|(i, bytes)| (fields_name[i].clone(), RawJsonb::new(bytes))),\n                    )\n                    .expect(\"failed to build jsonb object from tuple\")\n                }\n                _ => {\n                    let values = cast_scalars_to_variants(fields, tz, None);\n                    OwnedJsonb::build_object(\n                        values\n                            .iter()\n                            .enumerate()\n                            .map(|(i, bytes)| (format!(\"{}\", i + 1), RawJsonb::new(bytes))),\n                    )\n                    .expect(\"failed to build jsonb object from tuple\")\n                }\n            };\n            buf.extend_from_slice(owned_jsonb.as_ref());\n            return;\n        }\n        ScalarRef::Variant(bytes) => {\n            buf.extend_from_slice(bytes);\n            return;","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/expression/src/types/variant.rs#L359-L395","documentation":"This panic comes from an `expect` on `OwnedJsonb::build_object` while converting a Tuple scalar into a JSONB variant during `cast_scalar_to_variant`. The library assumes that building a JSON object from the tuple's field names and values cannot fail; the expect is an internal invariant check. If it fires, the jsonb builder rejected the object construction (e.g. an unencodable raw value or an internal builder error).","triggerScenarios":"Calling `cast_scalar_to_variant` on a `ScalarRef::Tuple` whose field count mismatches `fields_name` length (index out of range while mapping names), or where one of the field byte buffers cannot be embedded by `OwnedJsonb::build_object`. Reached via array_construct/object-style casts or `merge_result` aggregation of tuple values.","commonSituations":"Schema drift where a table's tuple type was altered but cached field names were not refreshed; mixing Databend versions where tuple encoding changed; corrupt or hand-crafted block data whose tuple payload does not match its declared type.","solutions":["Verify the tuple type's field names length matches the number of values passed to `cast_scalar_to_variant` (fields_name.len() == values.len()).","Re-check the source block's declared tuple schema against the actual column schema; refresh any cached schema/metas.","Reproduce with the specific tuple value and report to Databend with the value and cast path (this is an intended-to-be-impossible path).","As a stopgap, replace the `expect` with proper error propagation (`map_err(ErrorCode::Internal)`) in a patched build to get a diagnosable error instead of a panic."],"exampleFix":"// before\nOwnedJsonb::build_object(...).expect(\"failed to build jsonb object from tuple\")\n// after\nOwnedJsonb::build_object(...).map_err(|e| ErrorCode::Internal(format!(\"failed to build jsonb object from tuple: {e}\")))?","handlingStrategy":"validation","validationCode":"if fields_name.len() != values.len() {\n    return Err(ErrorCode::Internal(format!(\n        \"tuple field names ({}) != values ({})\",\n        fields_name.len(), values.len()\n    )));\n}","typeGuard":"fn tuple_fields_match(names: &[String], values: &[ScalarRef]) -> bool { names.len() == values.len() }","tryCatchPattern":null,"preventionTips":["Keep tuple type field names in sync with column schema after ALTERs","Avoid mixing Databend versions across a cluster","Cast unknown tuple payloads with explicit schema checks before VARIANT conversion"],"tags":["rust","jsonb","panic","type-cast"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}