risingwavelabs/risingwave · error

PostgreSQL snapshot column

Error message

PostgreSQL snapshot column `{name}` vector dimension mismatch: expected {}, got {}

What it means

Raised when a pgvector column decoded from a PostgreSQL snapshot has a different element count than the vector dimension declared in the RisingWave column (DataType::Vector(expected_size)). The strict converter refuses to pad, truncate, or reshape, and bails with expected vs actual dimension to keep vector data faithful during CDC snapshot reads.

Solutions

  1. Compare the 'got' dimension in the message against the RW column's declared dimension and fix the RW table definition (recreate/alter with the correct vector size).
  2. Normalize data in Postgres so every row's vector has the declared length, then re-run the snapshot.
  3. Add a dimension constraint on the Postgres side and correct offending rows.
  4. Re-run the snapshot after fixing; the strict converter will not silently truncate.

Example fix

// before: Postgres rows are 768-dim but RW declares 3
CREATE TABLE t (emb vector(3)) FROM pg ...;
// after
CREATE TABLE t (emb vector(768)) FROM pg ...;
Defensive patterns

Strategy: validation

Validate before calling

-- Postgres side: confirm all rows have the declared dimension
SELECT count(*) FROM t
WHERE cardinality(emb::text::float8[]) <> 768;

Try / catch

match result {
    Err(e) if e.to_string().contains("vector dimension mismatch") => {
        // parse expected/got from message, fix RW column dimension, restart snapshot
    }
    other => other?,
}

Prevention

When it happens

Trigger: `postgres_cell_to_scalar_impl_strict` processes a Vector-typed column during snapshot reads (via `postgres_row_to_owned_row_with_strict_pk`, `min_and_max`, `next_split_right_bound_exclusive`, `next_greater_bound`) and the decoded PgVectorAdapter's length differs from the RW column's declared vector size.

Common situations: The Postgres pgvector column was changed or created without a dimension constraint so rows contain mixed-length vectors; the RW table declares the wrong dimension; data written by older tooling with a different fixed size.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


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

Appendix: source

Thrown at src/connector/src/parser/postgres.rs:177

        DataType::Varchar | DataType::Int256 | DataType::Struct(_) => {
            match row
                .try_get::<_, Option<ScalarAdapter>>(i)
                .with_context(|| format!("failed to decode PostgreSQL snapshot column `{name}`"))?
            {
                Some(value) => value.into_scalar(data_type).map(Some).ok_or_else(|| {
                    anyhow!("failed to convert PostgreSQL snapshot column `{name}` to {data_type}")
                }),
                None => Ok(None),
            }
        }
        DataType::Vector(expected_size) => {
            match row
                .try_get::<_, Option<PgVectorAdapter>>(i)
                .with_context(|| format!("failed to decode PostgreSQL snapshot column `{name}`"))?
            {
                Some(PgVectorAdapter(v)) => {
                    if v.len() != *expected_size {
                        bail!(
                            "PostgreSQL snapshot column `{name}` vector dimension mismatch: \
                             expected {}, got {}",
                            expected_size,
                            v.len()
                        );
                    }
                    let finite = v
                        .into_iter()
                        .map(Finite32::try_from)
                        .collect::<Result<Vec<_>, _>>()
                        .map_err(anyhow::Error::msg)
                        .with_context(|| {
                            format!(
                                "PostgreSQL snapshot column `{name}` contains a non-finite vector \
                                 element"
                            )
                        })?;
                    Ok(Some(ScalarImpl::Vector(VectorVal::from(finite))))

View on GitHub (pinned to 6469eb736d)