risingwavelabs/risingwave · error

failed to convert PostgreSQL snapshot column

Error message

failed to convert PostgreSQL snapshot column `{name}` to {data_type}

What it means

Raised in the strict PostgreSQL snapshot cell converter when a decoded Postgres value (Varchar, Int256, or Struct branch) cannot be converted into the target RisingWave scalar type. The wire value was read from Postgres but the adapter's `into_scalar` returned None for the requested data type. It is a snapshot-read-time type incompatibility between the upstream column and the RW schema.

Solutions

  1. Check the RW table schema and align the column's declared data type with the actual Postgres column type.
  2. Re-create or ALTER the RW external table/sink so the column type matches what Postgres returns.
  3. If the value is legitimately convertible, cast the column in the snapshot read (e.g. SELECT col::text) and adjust the RW type.
  4. Upgrade RisingWave or file an issue if the Postgres type should be supported for that target type.

Example fix

// before: RW struct does not match the Postgres composite type
CREATE TABLE t (info struct<a int, b text>) FROM pg ...;
// after: align field types with the PG composite
CREATE TABLE t (info struct<a bigint, b varchar>) FROM pg ...;
Defensive patterns

Strategy: validation

Validate before calling

-- Verify RW column types match Postgres before creating the CDC table:
SELECT column_name, data_type, udt_name FROM information_schema.columns
WHERE table_name = 'my_table';
-- Ensure Varchar/Int256/Struct RW types match the PG column's udt_name.

Try / catch

match result {
    Err(e) if e.to_string().contains("failed to convert PostgreSQL snapshot column") => {
        // halt ingestion, alert on schema mismatch
    }
    other => other?,
}

Prevention

When it happens

Trigger: `postgres_cell_to_scalar_impl_strict` is called per cell during Postgres CDC snapshot reads (via `postgres_row_to_owned_row_with_strict_pk` and split-bound helpers `min_and_max`, `next_split_right_bound_exclusive`, `next_greater_bound`). Fires when the ScalarAdapter value decoded from a Varchar/Int256/Struct-typed column cannot map to that exact target DataType, e.g. a struct whose field types do not match the RW STRUCT definition.

Common situations: Schema drift between the RW table definition and the actual Postgres table (column type altered after table creation); an RW STRUCT whose fields do not match the Postgres composite type; a Postgres domain/custom type surfaced as a string in a column declared as Int256 or Struct.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

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

        | DataType::Timestamptz
        | DataType::Jsonb
        | DataType::Interval
        | DataType::Bytea => {
            // ScalarAdapter is also fine. But ScalarImpl is more efficient
            row.try_get::<_, Option<ScalarImpl>>(i)
                .with_context(|| format!("failed to decode PostgreSQL snapshot column `{name}`"))
        }
        DataType::Decimal => {
            // Decimal is more efficient than PgNumeric in ScalarAdapter
            try_handle_data_type!(row, i, name, Decimal)
        }
        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()
                        );
                    }

View on GitHub (pinned to 6469eb736d)