{"record":{"id":"e8fb069e93dad7da","repo":"risingwavelabs/risingwave","slug":"unexpected-statement","errorCode":null,"errorMessage":"unexpected statement: {:?}","messagePattern":"unexpected statement: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/frontend/src/handler/create_sink.rs","lineNumber":304,"sourceCode":"            sink_from_table_name = sink_table_name.clone();\n            direct_sink_from_name = None;\n            query\n        }\n    };\n\n    if is_iceberg_engine_internal && let Some((from_name, _)) = &direct_sink_from_name {\n        let (table, _) = get_table_catalog_by_table_name(session, from_name)?;\n        let pk_names = table.pk_column_names();\n        if pk_names.len() == 1 && pk_names[0].eq(ROW_ID_COLUMN_NAME) {\n            let [stmt]: [_; 1] = Parser::parse_sql(&format!(\n                \"select {} as {}, * from {}\",\n                ROW_ID_COLUMN_NAME, RISINGWAVE_ICEBERG_ROW_ID, from_name\n            ))\n            .context(\"unable to parse query\")?\n            .try_into()\n            .unwrap();\n            let Statement::Query(parsed_query) = stmt else {\n                panic!(\"unexpected statement: {:?}\", stmt);\n            };\n            query = parsed_query;\n        }\n    }\n\n    let (sink_database_id, sink_schema_id) =\n        session.get_database_and_schema_id_for_create(sink_schema_name.clone())?;\n\n    if since_timestamp_epoch.is_some() {\n        if sink_into_table_name.is_some() {\n            return Err(ErrorCode::BindError(format!(\n                \"`{SINK_SINCE_TIMESTAMP_OPTION}` does not support `CREATE SINK INTO TABLE`\"\n            ))\n            .into());\n        }\n        if is_iceberg_engine_internal {\n            return Err(ErrorCode::BindError(format!(\n                \"`{SINK_SINCE_TIMESTAMP_OPTION}` does not support iceberg engine internal sinks\"","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/frontend/src/handler/create_sink.rs#L286-L322","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Check the table/source name used for the iceberg table for characters that break the generated SQL; rename to a simple identifier.","Retry creation and capture the full SQL/log output to identify the generated statement.","If reproducible, report a bug — the internally generated `format!(\"SELECT ..., {} AS {} FROM {}\", ...)` string should always parse as a query.","Verify parser behavior with the same statement via `psql` EXPLAIN to isolate parsing issues."],"exampleFix":"// before (internal)\nlet Statement::Query(parsed_query) = stmt else {\n    panic!(\"unexpected statement: {:?}\", stmt);\n};\n// after\nlet Statement::Query(parsed_query) = stmt else {\n    return Err(anyhow!(\"expected query for iceberg sink input, got: {:?}\", stmt));\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// when automating iceberg table creation\ntry {\n    await client.execute(createIcebergTableSql);\n} catch (e) {\n    if (String(e).includes('unexpected statement')) {\n        // internal parser/plan issue: log SQL + RW version, retry or file a bug\n    } else { throw e; }\n}","preventionTips":["Use simple identifiers (no quotes/special chars) for iceberg engine tables.","Keep RisingWave updated — generated internal SQL is fixed in newer releases.","Capture the full SQL and logs when iceberg table creation fails to ease debugging."],"tags":["sink","iceberg","internal-error","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}