risingwavelabs/risingwave · critical

No result returned by `SELECT sys.fn_cdc_get_max_lsn()`

Error message

No result returned by `SELECT sys.fn_cdc_get_max_lsn()`

What it means

`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.

Source

Thrown at src/connector/src/source/cdc/external/sql_server.rs:234

#[derive(Debug)]
pub struct SqlServerExternalTableReader {
    rw_schema: Schema,
    pk_indices: Vec<usize>,
    field_names: String,
    client: tokio::sync::Mutex<SqlServerClient>,
}

impl ExternalTableReader for SqlServerExternalTableReader {
    async fn current_cdc_offset(&self) -> ConnectorResult<CdcOffset> {
        let mut client = self.client.lock().await;
        // start a transaction to read max start_lsn.
        let row = client
            .inner_client
            .simple_query(String::from("SELECT sys.fn_cdc_get_max_lsn()"))
            .await?
            .into_row()
            .await?
            .expect("No result returned by `SELECT sys.fn_cdc_get_max_lsn()`");
        // An example of change_lsn or commit_lsn: "00000027:00000ac0:0002" from debezium
        // sys.fn_cdc_get_max_lsn() returns a 10 bytes array, we convert it to a hex string here.
        let max_lsn = match row.try_get::<&[u8], usize>(0)? {
            Some(bytes) => {
                let mut hex_string = String::with_capacity(bytes.len() * 2 + 2);
                assert_eq!(
                    bytes.len(),
                    10,
                    "sys.fn_cdc_get_max_lsn() should return a 10 bytes array."
                );
                for byte in &bytes[0..4] {
                    hex_string.push_str(&format!("{:02x}", byte));
                }
                hex_string.push(':');
                for byte in &bytes[4..8] {
                    hex_string.push_str(&format!("{:02x}", byte));
                }
                hex_string.push(':');

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Enable CDC on the database and table: `EXEC sys.sp_cdc_enable_db;` then `EXEC sys.sp_cdc_enable_table ...`.
  2. Grant the connecting login sufficient privileges (db_owner or membership allowing fn_cdc_get_max_lsn).
  3. Verify connectivity and that the endpoint really is SQL Server (correct host/port/database).
  4. If the panic is unacceptable in your deployment, patch the code to return a ConnectorResult error instead of `expect`.

Example fix

// before
.expect("No result returned by `SELECT sys.fn_cdc_get_max_lsn()`");
// after
.ok_or_else(|| anyhow!("No result returned by `SELECT sys.fn_cdc_get_max_lsn()`; ensure CDC is enabled"))?
Defensive patterns

Strategy: validation

Validate before calling

-- Run before creating the source; must return one row with a non-NULL 10-byte value:
SELECT sys.fn_cdc_get_max_lsn();
SELECT name, is_cdc_enabled FROM sys.databases WHERE database_id = DB_ID();
SELECT name FROM sys.tables WHERE is_tracked_by_cdc = 1;

Try / catch

match client.simple_query("SELECT sys.fn_cdc_get_max_lsn()").await {
    Ok(v) => v,
    Err(e) => return Err(e.into()),
} // and treat an empty/NULL result as a config error, not a panic

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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