risingwavelabs/risingwave · error · SinkError::LanceDb
LanceDB pre-commit epoch {} does not match commit epoch {}
Error message
LanceDB pre-commit epoch {} does not match commit epoch {} What it means
During commit_data, the LanceDB sink deserializes the opaque pre-commit state written in pre_commit and compares its recorded epoch to the epoch the coordinator asks to commit. A mismatch means the commit belongs to a different (typically older) epoch than the one prepared — usually the consequence of a recovery/restart where a stale prepared transaction is replayed against a new epoch.
Source
Thrown at src/connector/src/sink/lancedb.rs:750
LanceDbPreCommitMetadata {
sink_id: self.sink_id.clone(),
epoch,
fragments,
}
.try_into_bytes()?,
))
}
async fn commit_data(&mut self, epoch: u64, commit_metadata: Vec<u8>) -> Result<()> {
tracing::debug!("Starting LanceDB two-phase commit in epoch {epoch}.");
if commit_metadata.is_empty() {
return Ok(());
}
let pre_commit_metadata = LanceDbPreCommitMetadata::try_from_bytes(&commit_metadata)?;
if pre_commit_metadata.epoch != epoch {
return Err(SinkError::LanceDb(anyhow!(
"LanceDB pre-commit epoch {} does not match commit epoch {}",
pre_commit_metadata.epoch,
epoch
)));
}
if pre_commit_metadata.sink_id != self.sink_id {
return Err(SinkError::LanceDb(anyhow!(
"LanceDB pre-commit sink id {} does not match coordinator sink id {}",
pre_commit_metadata.sink_id,
self.sink_id
)));
}
let transaction_properties = pre_commit_metadata.transaction_properties();
self.commit_fragments(
epoch,
pre_commit_metadata.fragments,
Some(transaction_properties),View on GitHub (pinned to 6469eb736d)
Solutions
- Verify whether the epoch's data already landed in LanceDB before the error — if so, the stale prepared state can be safely discarded
- Restart/recover the sink so pre_commit state is re-created at the current epoch
- Ensure only one coordinator commits to the sink at a time (check for duplicate sink worker assignments)
- If persistent after a single clean restart, report — it may indicate lost/incorrect pre-commit metadata
Defensive patterns
Strategy: retry
Validate before calling
// before committing, verify metadata epoch matches
let meta = LanceDbPreCommitMetadata::try_from_bytes(&commit_metadata)?;
if meta.epoch != epoch { /* stale prepared txn: verify data landed, then discard */ } Type guard
fn is_epoch_mismatch(err: &SinkError) -> bool {
matches!(err, SinkError::LanceDb(e) if e.to_string().contains("does not match commit epoch"))
} Try / catch
match commit_result {
Err(e) if e.to_string().contains("does not match commit epoch") => {
// stale prepared state from before recovery: verify data, then proceed with new epoch
}
other => other,
} Prevention
- After a crash/recovery, verify whether the previous epoch's data landed in LanceDB before replaying
- Ensure single-coordinator semantics for the sink (no duplicated barrier commits)
- Check that pre-commit metadata persists and restores correctly across restarts
When it happens
Trigger: pre_commit stored epoch E1 in LanceDbPreCommitMetadata; the coordinator later calls commit_data with epoch E2 != E1, e.g. after a failover/restart, or a replayed commit for an epoch that was already committed/aborted.
Common situations: Recovery after a meta-node failure replaying old commit epochs; duplicated barrier delivery; retries of an already-committed epoch.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- LanceDB pre-commit sink id {} does not match coordinator sin
- Lance fragment write task stopped before accepting a record
- LanceDB sink does not support schema change
- (underlying lancedb::Error)
- Schema change is not implemented for two-phase commit coordi
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/c23ceeef5363b087.
Report an issue: GitHub.