risingwavelabs/risingwave · error · SinkError::BigQuery

VARIANT is not supported for BigQuery sink.

Error message

VARIANT is not supported for BigQuery sink.

What it means

RisingWave's VARIANT (semi-structured) type has no BigQuery counterpart in this connector's type mapping, so `get_string_and_check_support_from_datatype` rejects any sink schema containing a VARIANT column.

Source

Thrown at src/connector/src/sink/big_query.rs:423

            DataType::Timestamp => Ok("DATETIME".to_owned()),
            DataType::Timestamptz => Ok("TIMESTAMP".to_owned()),
            DataType::Interval => Ok("INTERVAL".to_owned()),
            DataType::Struct(structs) => {
                let mut elements_vec = vec![];
                for (name, datatype) in structs.iter() {
                    let element_string =
                        Self::get_string_and_check_support_from_datatype(datatype)?;
                    elements_vec.push(format!("{} {}", name, element_string));
                }
                Ok(format!("STRUCT<{}>", elements_vec.join(", ")))
            }
            DataType::List(l) => {
                let element_string = Self::get_string_and_check_support_from_datatype(l.elem())?;
                Ok(format!("ARRAY<{}>", element_string))
            }
            DataType::Bytea => Ok("BYTES".to_owned()),
            DataType::Jsonb => Ok("JSON".to_owned()),
            DataType::Variant => Err(SinkError::BigQuery(anyhow::anyhow!(
                "VARIANT is not supported for BigQuery sink."
            ))),
            DataType::Serial => Ok("INT64".to_owned()),
            DataType::Int256 => Err(SinkError::BigQuery(anyhow::anyhow!(
                "INT256 is not supported for BigQuery sink."
            ))),
            DataType::Map(_) => Err(SinkError::BigQuery(anyhow::anyhow!(
                "MAP is not supported for BigQuery sink."
            ))),
            DataType::Vector(_) => Err(SinkError::BigQuery(anyhow::anyhow!(
                "VECTOR is not supported for BigQuery sink."
            ))),
        }
    }

    fn map_field(rw_field: &Field) -> Result<TableFieldSchema> {
        let tfs = match &rw_field.data_type {
            DataType::Boolean => TableFieldSchema::bool(&rw_field.name),

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Convert the VARIANT column to JSONB in the MV (CAST(col AS JSONB)) which maps to BigQuery JSON
  2. Or extract the needed fields from the VARIANT into typed columns
  3. Recreate the sink after the schema change

Example fix

-- before
CREATE MATERIALIZED VIEW mv AS SELECT v FROM t; -- v is VARIANT
-- after
CREATE MATERIALIZED VIEW mv AS SELECT CAST(v AS JSONB) AS v FROM t;
Defensive patterns

Strategy: validation

Validate before calling

SELECT column_name FROM information_schema.columns
WHERE table_name = 'mv' AND udt_name = 'variant';
-- must return zero rows before CREATE SINK

Type guard

fn sink_ready(field: &Field) -> bool { !matches!(field.data_type(), DataType::Variant) }

Try / catch

match get_string_and_check_support_from_datatype(&dt) {
    Err(e) if e.to_string().contains("VARIANT is not supported") => {
        eprintln!("cast VARIANT to JSONB in the MV");
    }
    _ => {}
}

Prevention

When it happens

Trigger: Creating a BigQuery sink on a relation with a VARIANT column (e.g. from a Snowflake-compatible or JSON-ingested source); validation enumerates all fields and errors on the VARIANT one.

Common situations: Semi-structured payloads ingested as VARIANT being piped to BigQuery; users expecting automatic conversion to BigQuery JSON.

Related errors


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