{"record":{"id":"5eb43b4333153834","repo":"risingwavelabs/risingwave","slug":"no-result-returned-by-select-sys-fn-cdc-get-max-l","errorCode":null,"errorMessage":"No result returned by `SELECT sys.fn_cdc_get_max_lsn()`","messagePattern":"No result returned by `SELECT sys\\.fn_cdc_get_max_lsn\\(\\)`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/connector/src/source/cdc/external/sql_server.rs","lineNumber":234,"sourceCode":"#[derive(Debug)]\npub struct SqlServerExternalTableReader {\n    rw_schema: Schema,\n    pk_indices: Vec<usize>,\n    field_names: String,\n    client: tokio::sync::Mutex<SqlServerClient>,\n}\n\nimpl ExternalTableReader for SqlServerExternalTableReader {\n    async fn current_cdc_offset(&self) -> ConnectorResult<CdcOffset> {\n        let mut client = self.client.lock().await;\n        // start a transaction to read max start_lsn.\n        let row = client\n            .inner_client\n            .simple_query(String::from(\"SELECT sys.fn_cdc_get_max_lsn()\"))\n            .await?\n            .into_row()\n            .await?\n            .expect(\"No result returned by `SELECT sys.fn_cdc_get_max_lsn()`\");\n        // An example of change_lsn or commit_lsn: \"00000027:00000ac0:0002\" from debezium\n        // sys.fn_cdc_get_max_lsn() returns a 10 bytes array, we convert it to a hex string here.\n        let max_lsn = match row.try_get::<&[u8], usize>(0)? {\n            Some(bytes) => {\n                let mut hex_string = String::with_capacity(bytes.len() * 2 + 2);\n                assert_eq!(\n                    bytes.len(),\n                    10,\n                    \"sys.fn_cdc_get_max_lsn() should return a 10 bytes array.\"\n                );\n                for byte in &bytes[0..4] {\n                    hex_string.push_str(&format!(\"{:02x}\", byte));\n                }\n                hex_string.push(':');\n                for byte in &bytes[4..8] {\n                    hex_string.push_str(&format!(\"{:02x}\", byte));\n                }\n                hex_string.push(':');","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/source/cdc/external/sql_server.rs#L216-L252","documentation":"`current_cdc_offset` queries `SELECT sys.fn_cdc_get_max_lsn()` to obtain the current maximum LSN as the starting CDC offset. It panics via `.expect` if the query yields no row at all — meaning the CDC metadata function returned nothing, which indicates CDC is not enabled or the database is unreachable/misconfigured.","triggerScenarios":"Starting/resuming a SQL Server CDC source when the query returns zero rows: CDC not enabled on the database/table, missing db_owner/sysadmin privileges for fn_cdc_get_max_lsn, or connecting to a non-SQL-Server endpoint.","commonSituations":"Forgot to run `EXEC sys.sp_cdc_enable_db` / `sp_cdc_enable_table`; connecting with a low-privilege login; Azure SQL database without CDC enabled; wrong port pointing to another service.","solutions":["Enable CDC on the database and table: `EXEC sys.sp_cdc_enable_db;` then `EXEC sys.sp_cdc_enable_table ...`.","Grant the connecting login sufficient privileges (db_owner or membership allowing fn_cdc_get_max_lsn).","Verify connectivity and that the endpoint really is SQL Server (correct host/port/database).","If the panic is unacceptable in your deployment, patch the code to return a ConnectorResult error instead of `expect`."],"exampleFix":"// before\n.expect(\"No result returned by `SELECT sys.fn_cdc_get_max_lsn()`\");\n// after\n.ok_or_else(|| anyhow!(\"No result returned by `SELECT sys.fn_cdc_get_max_lsn()`; ensure CDC is enabled\"))?","handlingStrategy":"validation","validationCode":"-- Run before creating the source; must return one row with a non-NULL 10-byte value:\nSELECT sys.fn_cdc_get_max_lsn();\nSELECT name, is_cdc_enabled FROM sys.databases WHERE database_id = DB_ID();\nSELECT name FROM sys.tables WHERE is_tracked_by_cdc = 1;","typeGuard":null,"tryCatchPattern":"match client.simple_query(\"SELECT sys.fn_cdc_get_max_lsn()\").await {\n    Ok(v) => v,\n    Err(e) => return Err(e.into()),\n} // and treat an empty/NULL result as a config error, not a panic","preventionTips":["Always enable CDC at DB and table level (sp_cdc_enable_db, sp_cdc_enable_table) first.","Connect with a login that has db_owner or higher.","Keep SQL Server Agent running so the capture job maintains LSNs."],"tags":["cdc","sql-server","lsn","panic"],"backgroundTag":"empty-result-set","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"}