risingwavelabs/risingwave · error
cannot convert {} as {ty} to variant
Error message
cannot convert {} as {ty} to variant What it means
append_datum_value converts a RisingWave scalar Datum into a Variant value. The match covers all supported scalar/type combinations; any (value, type) pair outside the supported set (e.g. appending unsupported types like interval or serial as variant) hits this catch-all bail. `value.get_ident()` gives a human-readable value description and `ty` the type.
Source
Thrown at src/common/src/types/variant.rs:719
(ScalarRefImpl::Map(v), DataType::Map(map_type)) => {
let mut object = builder
.try_new_object()
.context("failed to create variant map object")?;
let entries = v
.iter()
.map(|(key, value)| {
let field = key.to_text_with_type(map_type.key());
(field, value)
})
.sorted_by(|a, b| a.0.cmp(&b.0))
.collect_vec();
for (field, value) in entries {
let mut field_builder = ObjectFieldBuilder::new(field.as_str(), &mut object);
append_datum_value(value, map_type.value(), &mut field_builder)?;
}
object.finish();
}
(value, ty) => bail!("cannot convert {} as {ty} to variant", value.get_ident()),
}
Ok(())
}
/// Variant objects require unique field names, but RisingWave struct types allow duplicates.
/// Callers iterate fields in name order, so comparing against the previous name suffices.
fn reject_duplicate_field(previous: Option<&str>, field_name: &str) -> anyhow::Result<()> {
if previous == Some(field_name) {
bail!("variant object cannot have duplicate field name `{field_name}`");
}
Ok(())
}
fn append_struct(
value: super::StructRef<'_>,
struct_type: &StructType,
builder: &mut impl VariantBuilderExt,
) -> anyhow::Result<()> {View on GitHub (pinned to 6469eb736d)
Solutions
- Cast or exclude the unsupported type before conversion (e.g. cast interval to varchar first)
- Add an arm in append_datum_value for the missing type if you own the code
- Filter rows/types in SQL to supported variant types
Example fix
// before Variant::try_from_scalar_ref(&interval_datum)?; // bails // after Variant::try_from_scalar_ref(&varchar_datum)?; // cast interval to varchar first
Defensive patterns
Strategy: try-catch
Validate before calling
fn variant_supported(ty: &DataType) -> bool {
!matches!(ty, DataType::Interval | DataType::Serial)
} Try / catch
match append_datum_value(&datum, &ty, &mut builder) {
Err(e) if e.to_string().contains("to variant") => {
// fall back: convert value to its string form
append_datum_value(&datum.cast_to(&DataType::Varchar).unwrap(), &DataType::Varchar, &mut builder)?;
}
r => r?,
} Prevention
- Cast unsupported types (interval, serial) to varchar before variant conversion
- Keep a list of types supported by append_datum_value and validate schemas against it
- Cover new types with an arm in the conversion match when adding them
When it happens
Trigger: Calling try_from_scalar_ref or append_datum_value with a type/value combination not implemented in the conversion match (e.g. converting an interval or serial datum into a Variant).
Common situations: Building variant columns from tables containing types without a Variant representation, or copy/compute jobs that cast data to Variant without first filtering unsupported types.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- unsupported JSON number: {v}
- variant object cannot have duplicate field name `{field_name
- invalid variant path `{original_path}`
- Invalid variant encoding
- creating an Iceberg table with VARIANT column `{}` requires
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/06fd6e87c31637c8.
Report an issue: GitHub.