risingwavelabs/risingwave · error · SinkError::Config
Primary key not defined for upsert clickhouse sink (please d
Error message
Primary key not defined for upsert clickhouse sink (please define in `primary_key` field)
What it means
The ClickHouse sink's validate() requires an upsert sink to have a primary key. If the sink is not append-only and no primary key columns were derived (pk_indices empty), validation fails, telling users to define it via the `primary_key` field.
Source
Thrown at src/connector/src/sink/clickhouse.rs:568
ck_column.name, fields_type, ck_column.r#type
)));
}
Ok(())
}
}
impl Sink for ClickHouseSink {
type LogSinker = DecoupleCheckpointLogSinkerOf<ClickHouseSinkWriter>;
const SINK_NAME: &'static str = CLICKHOUSE_SINK;
crate::impl_validate_sink_unknown_fields!();
async fn validate(&self) -> Result<()> {
// For upsert clickhouse sink, the primary key must be defined.
if !self.is_append_only && self.pk_indices.is_empty() {
return Err(SinkError::Config(anyhow!(
"Primary key not defined for upsert clickhouse sink (please define in `primary_key` field)"
)));
}
// check reachability
let client = self.config.common.build_client()?;
let (clickhouse_column, clickhouse_engine) =
query_column_engine_from_ck(client, &self.config).await?;
if clickhouse_engine.is_shared_tree() {
risingwave_common::license::Feature::ClickHouseSharedEngine
.check_available()
.map_err(|e| anyhow::anyhow!(e))?;
}
if !self.is_append_only
&& !clickhouse_engine.is_collapsing_engine()
&& !clickhouse_engine.is_delete_replacing_engine()View on GitHub (pinned to 6469eb736d)
Solutions
- Add primary_key='col1,col2' to the WITH options listing the key columns.
- Switch the sink to type='append-only' if upsert semantics are not needed.
- Create the sink from a materialized view that includes a primary key.
Example fix
// before WITH (connector='clickhouse', type='upsert', ...) // after WITH (connector='clickhouse', type='upsert', primary_key='user_id', ...)
Defensive patterns
Strategy: validation
Validate before calling
if (props.type === 'upsert' && !props.primary_key) throw new Error("ClickHouse upsert sink requires primary_key in WITH options"); Prevention
- Always pair type='upsert' with an explicit primary_key option.
- Ensure the source relation has a primary key when sinking in upsert mode.
- Use append-only sinks when no key semantics are needed.
When it happens
Trigger: CREATE SINK ... WITH (connector='clickhouse', type='upsert', ...) where neither the WITH options nor the underlying table supply primary key columns, leaving pk_indices empty.
Common situations: Sinking a table without a primary key in upsert mode; forgetting the `primary_key` property; expecting ClickHouse's own ORDER BY to substitute for a RisingWave primary key.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- primary key must be specified for upsert iceberg sink
- VARIANT column `{}` cannot be used as the primary key of an
- Primary key not defined for upsert mongodb sink (please defi
- collection.name.field {} must not be equal to the primary ke
- Primary key not defined for upsert SQL Server sink (please d
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/9e763a8c8a229222.
Report an issue: GitHub.