risingwavelabs/risingwave · error · SinkError::Remote
Only Es sink supports struct, got {:?}: {:?}
Error message
Only Es sink supports struct, got {:?}: {:?} What it means
During remote sink column validation, RisingWave rejects any column whose type is Struct unless the remote sink is an Elasticsearch (Es) sink. The JVM-based remote sink protocol can only serialize struct columns for the ES connector, so any other remote sink with a Struct column fails validation before the sink is created.
Source
Thrown at src/connector/src/sink/remote.rs:227
| DataType::Interval
| DataType::Jsonb
| DataType::Bytea => Ok(()),
DataType::List(list) => {
if is_remote_es_sink(sink_name) || matches!(list.elem(), DataType::Int16 | DataType::Int32 | DataType::Int64 | DataType::Float32 | DataType::Float64 | DataType::Varchar){
Ok(())
} else{
Err(SinkError::Remote(anyhow!(
"Remote sink only supports list<int16, int32, int64, float, double, varchar>, got {:?}: {:?}",
col.name,
col.data_type,
)))
}
},
DataType::Struct(_) => {
if is_remote_es_sink(sink_name){
Ok(())
}else{
Err(SinkError::Remote(anyhow!(
"Only Es sink supports struct, got {:?}: {:?}",
col.name,
col.data_type,
)))
}
},
DataType::Vector(_) |
DataType::Serial | DataType::Int256 | DataType::Map(_) | DataType::Variant => Err(SinkError::Remote(anyhow!(
"remote sink supports Int16, Int32, Int64, Float32, Float64, Boolean, Decimal, Time, Date, Interval, Jsonb, Timestamp, Timestamptz, Bytea, List and Varchar, (Es sink support Struct) got {:?}: {:?}",
col.name,
col.data_type,
)))}})?;
let jvm = Jvm::get_or_init()?;
let sink_param = param.to_proto();
spawn_blocking(move || -> anyhow::Result<()> {
execute_with_jni_env(jvm, |env| {View on GitHub (pinned to 6469eb736d)
Solutions
- Use an Elasticsearch remote sink if the data genuinely contains struct columns.
- Flatten the struct column into primitive columns (e.g. via flatten or explicit field selection) before sinking.
- Cast the struct column to a JSONB/VARCHAR column, which remote sinks support.
- If the sink actually is ES, verify the sink name/connector matches what is_remote_es_sink expects.
Example fix
-- before CREATE SINK s FROM mv WITH (connector = 'jdbc', ...); -- mv has STRUCT column -- after (flatten) CREATE SINK s AS SELECT (col).field_a AS field_a, (col).field_b AS field_b FROM mv WITH (connector = 'jdbc', ...);
Defensive patterns
Strategy: validation
Validate before calling
-- before CREATE SINK: check for struct columns SELECT column_name, data_type FROM rw_catalog.rw_columns WHERE relation_id = 'your_mv_id' AND data_type LIKE 'struct%'; -- if rows returned, use an ES sink or flatten/cast those columns
Prevention
- Check the sink schema for STRUCT columns when using non-ES remote sinks
- Prefer flattening nested structs into primitives at the MV layer
- Validate the sink plan with EXPLAIN or a dry-run before creating it
When it happens
Trigger: Creating/validating a remote (JVM) sink whose schema contains a DataType::Struct column while sink_name is not recognized as a remote ES sink (is_remote_es_sink returns false), via CREATE SINK with a struct-typed column.
Common situations: Users sink a table/materialized view containing a nested struct (e.g. from JSON ingestion) into a non-ES remote sink like Kafka via JDBC; changing a column to STRUCT after originally targeting ES.
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
- Field '{field}' is not allowed to be altered on the fly for
- remote sink supports Int16, Int32, Int64, Float32, Float64,
- unsupported sink type {}
- connector not specified when alter sink
- Unknown source connector: {connector_name}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/e4adc7ff812d0298.
Report an issue: GitHub.