risingwavelabs/risingwave · error

SQL Server max_lsn is NULL

Error message

SQL Server max_lsn is NULL

What it means

After reading the row, the max_lsn column is Option<&[u8]>; if it is NULL (None), this error is thrown because a hex-encoded max LSN string is mandatory for CDC monitoring. `sys.fn_cdc_get_max_lsn` returns NULL when CDC is not enabled on the database.

Source

Thrown at src/connector/src/source/cdc/enumerator/mod.rs:348

            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(':');
            for byte in &bytes[8..10] {
                hex_string.push_str(&format!("{:02x}", byte));
            }
            Ok(hex_string)
        };

        let max_lsn = row
            .try_get::<&[u8], usize>(0)?
            .map(lsn_bytes_to_hex)
            .transpose()?
            .ok_or_else(|| anyhow!("SQL Server max_lsn is NULL"))?;
        let min_lsn = row
            .try_get::<&[u8], usize>(1)?
            .map(lsn_bytes_to_hex)
            .transpose()?
            .ok_or_else(|| anyhow!("SQL Server min_lsn is NULL"))?;

        Ok(Some((min_lsn, max_lsn)))
    }

    async fn monitor_sql_server_lsns(&mut self) -> ConnectorResult<()> {
        let lsns = self.query_sql_server_lsns().await.with_context(|| {
            format!(
                "failed to query SQL Server LSNs for source {}",
                self.source_id
            )
        })?;
        if let Some((min_lsn, max_lsn)) = lsns {
            let labels = vec![self.source_id.to_string()];

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Ensure database-level CDC is enabled (`sys.sp_cdc_enable_db`) so `fn_cdc_get_max_lsn` returns a value
  2. Start/verify SQL Server Agent and the `cdc.<db>_capture` job
  3. Re-initialize CDC on restored databases (re-run sp_cdc_enable_db/table and jobs)
  4. Confirm the query targets the correct database

Example fix

// ensure capture job runs
EXEC sys.sp_cdc_start_job @job_type = N'capture';
Defensive patterns

Strategy: validation

Validate before calling

// Precheck on SQL Server:
// SELECT sys.fn_cdc_get_max_lsn() IS NULL AS max_lsn_missing;

Try / catch

match res {
    Err(e) if e.to_string().contains("max_lsn is NULL") => {
        warn!("CDC max LSN unavailable; ensure CDC and capture job are enabled");
    }
    other => other?,
}

Prevention

When it happens

Trigger: The LSN query returns a row whose first column (max_lsn from `sys.fn_cdc_get_max_lsn()`) is NULL — CDC metadata absent for the database.

Common situations: CDC enabled on the table's capture list but database-level CDC max LSN is uninitialized; SQL Server Agent capture job has never run; querying a restored/attached database where CDC jobs were not recreated.

Related errors


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