risingwavelabs/risingwave · error · SinkError::Config

Primary key not defined for upsert mongodb sink (please defi

Error message

Primary key not defined for upsert mongodb sink (please define in `primary_key` field)

What it means

When a MongoDB sink is created in upsert mode (the stream is not append-only), RisingWave requires an explicit primary key so it can build the MongoDB `_id` field for upserts. `validate` throws this error at sink creation when `pk_indices` is empty, meaning no `primary_key` was defined in the sink's WITH options. Without a PK, upsert semantics cannot be expressed in MongoDB.

Source

Thrown at src/connector/src/sink/mongodb.rs:274

impl TryFrom<SinkParam> for MongodbSink {
    type Error = SinkError;

    fn try_from(param: SinkParam) -> std::result::Result<Self, Self::Error> {
        MongodbSink::new(param)
    }
}

impl Sink for MongodbSink {
    type LogSinker = AsyncTruncateLogSinkerOf<MongodbSinkWriter>;

    const SINK_NAME: &'static str = MONGODB_SINK;

    crate::impl_validate_sink_unknown_fields!();

    async fn validate(&self) -> Result<()> {
        if !self.is_append_only {
            if self.pk_indices.is_empty() {
                return Err(SinkError::Config(anyhow!(
                    "Primary key not defined for upsert mongodb sink (please define in `primary_key` field)"
                )));
            }

            // checking if there is a non-pk field's name is `_id`
            if self
                .schema
                .fields
                .iter()
                .enumerate()
                .any(|(i, field)| !self.pk_indices.contains(&i) && field.name == MONGODB_PK_NAME)
            {
                return Err(SinkError::Config(anyhow!(
                    "_id field must be the sink's primary key, but a non primary key field name is _id",
                )));
            }

            // assume the sink's pk is (a, b) and then the data written to mongodb will be

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Add `primary_key='your_column'` (or a comma-separated list) to the WITH options of the CREATE SINK statement.
  2. If the sink should only receive inserts, ensure the upstream stream is append-only (e.g., sink from an append-only source) or use append-only mode so PK is not required.
  3. If upserting on the full row is intended, specify all columns as the primary key.

Example fix

-- before
CREATE SINK s FROM mv INTO mongodb WITH (
  connector='mongodb', url='mongodb://localhost:27017', collection='c'
);
-- after
CREATE SINK s FROM mv INTO mongodb WITH (
  connector='mongodb', url='mongodb://localhost:27017', collection='c',
  primary_key='id'
);
Defensive patterns

Strategy: validation

Validate before calling

// Before creating the sink, ensure upsert sinks declare a primary key
const isAppendOnly = /* determined from source */ false;
const hasPk = sinkOptions.primary_key != null && sinkOptions.primary_key.length > 0;
if (!isAppendOnly && !hasPk) {
  throw new Error("MongoDB upsert sink requires `primary_key` in WITH options");
}

Prevention

When it happens

Trigger: Creating a `CREATE SINK ... INTO mongodb ...` sink without a `primary_key` option while the source/materialized view is not append-only (i.e., it can emit UPDATE/DELETE events).

Common situations: Developers forgetting to add `primary_key='col'` to the WITH clause when the upstream is a materialized view with updates; assuming a PK on the source table is automatically inherited by the sink.

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


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