risingwavelabs/risingwave · error

unexpected statement: {:?}

Error message

unexpected statement: {:?}

What it means

`gen_sink_plan` panics with "unexpected statement" while rewriting the query for an iceberg-engine table sink. The source query text is re-parsed and the code asserts the result is `Statement::Query`; any other statement kind (INSERT, CREATE, etc.) hits the `panic!`. It guards the invariant that sink input is always a SELECT/query at this point.

Source

Thrown at src/frontend/src/handler/create_sink.rs:304

            sink_from_table_name = sink_table_name.clone();
            direct_sink_from_name = None;
            query
        }
    };

    if is_iceberg_engine_internal && let Some((from_name, _)) = &direct_sink_from_name {
        let (table, _) = get_table_catalog_by_table_name(session, from_name)?;
        let pk_names = table.pk_column_names();
        if pk_names.len() == 1 && pk_names[0].eq(ROW_ID_COLUMN_NAME) {
            let [stmt]: [_; 1] = Parser::parse_sql(&format!(
                "select {} as {}, * from {}",
                ROW_ID_COLUMN_NAME, RISINGWAVE_ICEBERG_ROW_ID, from_name
            ))
            .context("unable to parse query")?
            .try_into()
            .unwrap();
            let Statement::Query(parsed_query) = stmt else {
                panic!("unexpected statement: {:?}", stmt);
            };
            query = parsed_query;
        }
    }

    let (sink_database_id, sink_schema_id) =
        session.get_database_and_schema_id_for_create(sink_schema_name.clone())?;

    if since_timestamp_epoch.is_some() {
        if sink_into_table_name.is_some() {
            return Err(ErrorCode::BindError(format!(
                "`{SINK_SINCE_TIMESTAMP_OPTION}` does not support `CREATE SINK INTO TABLE`"
            ))
            .into());
        }
        if is_iceberg_engine_internal {
            return Err(ErrorCode::BindError(format!(
                "`{SINK_SINCE_TIMESTAMP_OPTION}` does not support iceberg engine internal sinks"

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check the table/source name used for the iceberg table for characters that break the generated SQL; rename to a simple identifier.
  2. Retry creation and capture the full SQL/log output to identify the generated statement.
  3. If reproducible, report a bug — the internally generated `format!("SELECT ..., {} AS {} FROM {}", ...)` string should always parse as a query.
  4. Verify parser behavior with the same statement via `psql` EXPLAIN to isolate parsing issues.

Example fix

// before (internal)
let Statement::Query(parsed_query) = stmt else {
    panic!("unexpected statement: {:?}", stmt);
};
// after
let Statement::Query(parsed_query) = stmt else {
    return Err(anyhow!("expected query for iceberg sink input, got: {:?}", stmt));
};
Defensive patterns

Strategy: try-catch

Try / catch

// when automating iceberg table creation
try {
    await client.execute(createIcebergTableSql);
} catch (e) {
    if (String(e).includes('unexpected statement')) {
        // internal parser/plan issue: log SQL + RW version, retry or file a bug
    } else { throw e; }
}

Prevention

When it happens

Trigger: Creating an iceberg-engine table (`CREATE TABLE ... WITH (engine = 'iceberg')` path, via `create_iceberg_engine_table`) where the generated `from_name` based query fails to parse as a query — e.g. the interpolated `ROW_ID` column SQL string produces a non-query statement or the parser returns a different statement variant.

Common situations: Iceberg engine table creation with unusual table/source names that break the generated SQL; parser behavior changes after upgrades; bugs in the internally generated query string (not user SQL directly).

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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