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

  1. Cast or exclude the unsupported type before conversion (e.g. cast interval to varchar first)
  2. Add an arm in append_datum_value for the missing type if you own the code
  3. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/06fd6e87c31637c8. Report an issue: GitHub.