clockworklabs/SpacetimeDB · error · io::Error
No valid commit found in index up to key
Error message
No valid commit found in index up to key: {candidate_last_key} What it means
The index-seek path walks offset-index entries backwards from the requested transaction offset, validating each candidate commit against segment data. If every candidate key down to candidate_last_key fails to validate (reaching key 0), it gives up with io::ErrorKind::InvalidData 'No valid commit found in index up to key: N'. The index has no entry consistent with the segment.
Solutions
- Delete the offset index files and reopen the log to force a rebuild from segment data
- Read by scanning the segment sequentially instead of using the index for the problematic offset
- Verify segment and index files come from the same backup generation
- If the offset genuinely predates the segment, request a lower segment offset instead
Defensive patterns
Strategy: fallback
Type guard
fn is_index_exhausted(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::InvalidData && err.to_string().contains("No valid commit found in index")
} Try / catch
match reader.seek_tx(offset) {
Ok(pos) => Ok(pos),
Err(e) if is_index_exhausted(&e) => {
// drop the index, rescan the segment from its start
let _ = std::fs::remove_file(index_path);
reader.rescan_segment()
}
Err(e) => Err(e),
} Prevention
- Expose and schedule an index-rebuild maintenance step after restores
- Validate that segment and index files in a restored directory share the same generation
- Prefer scan-based reads for very old offsets instead of forcing index seeks
When it happens
Trigger: An offset index wholly stale relative to its segment (e.g. restored from a different generation); seeking a transaction offset older than anything the index can validate; a segment whose early records were corrupted so every candidate fails.
Common situations: Partial restores mixing segment and index files from different points in time; index never rebuilt after a prior corruption event; seeking to very old offsets for audit/backfill reads.
Related errors
- failed to decode commit
- mismatch key in index offset file: expected=
- mismatched key in offset index file
- all-zeroes commit header
- Failed to truncate offset index
AI-assisted analysis of clockworklabs/SpacetimeDB@3653d2ed49 (2026-08-20).
Data as JSON: /api/errors/145fdf42463d9d7b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/commitlog/src/segment.rs:754
},
size_in_bytes: byte_offset + commit.size_in_bytes,
max_epoch: commit.epoch,
max_commit_offset: commit.tx_range.start,
max_commit: Some(commit),
});
}
// `TxOffset` at `byte_offset` is not valid, so try with previous entry
Err(_) => {
candidate_last_key = key.saturating_sub(1);
if candidate_last_key == 0 {
break;
}
}
}
}
Err(io::Error::new(
ErrorKind::InvalidData,
format!("No valid commit found in index up to key: {candidate_last_key}"),
))
}
/// Validates and decodes a commit at `byte_offset` in the segment.
///
/// # Returns
/// * `Ok(commit::Metadata)` - If a valid commit is found with matching transaction offset
/// * `Err` - If commit can't be decoded or has mismatched transaction offset
fn validate_commit_at_offset<R: io::Read + io::Seek>(
reader: &mut R,
tx_offset: TxOffset,
byte_offset: u64,
) -> io::Result<commit::Metadata> {
reader.seek(SeekFrom::Start(byte_offset))?;
let commit = commit::Metadata::extract(reader)?
.ok_or_else(|| io::Error::new(ErrorKind::InvalidData, "failed to decode commit"))?;View on GitHub (pinned to 3653d2ed49)