influxdata/influxdb · error
row_delete_predicate_version exceeds u64
Error message
row_delete_predicate_version exceeds u64
What it means
A `.expect(...)` panic in the v2->v3 migration while converting a `NodeSnapshot` into a `RegisterNode` record: the v2 `row_delete_predicate_version` value is converted with `u64::try_from` and asserted to fit. The type in the v2 snapshot is apparently signed/wider, and a negative or out-of-range value cannot be represented as u64 in v3.
Solutions
- Inspect the node entries in the v2 catalog and fix/reset `row_delete_predicate_version` to a valid non-negative version (usually 0 or 1).
- Restore the v2 catalog object from a known-good backup.
- Replace the `expect` with a fallible mapping that returns `MigrationError::Unexpected` so migration fails gracefully.
- Check for tooling/scripts writing sentinel (-1) versions into the v2 catalog and remove them.
Example fix
// before
.expect("row_delete_predicate_version exceeds u64"),
// after
row_delete_predicate_version: u64::try_from(self.row_delete_predicate_version)
.map_err(|_| MigrationError::Unexpected(anyhow::anyhow!("invalid row_delete_predicate_version {}", self.row_delete_predicate_version)))?, Defensive patterns
Strategy: validation
Validate before calling
fn row_delete_predicate_version_is_valid(v: i64) -> bool { v >= 0 } Type guard
fn as_u64(v: i64) -> Option<u64> { u64::try_from(v).ok() } Try / catch
// panic path; guard any code that writes this field
let version = as_u64(raw).ok_or_else(|| anyhow!("row_delete_predicate_version must be non-negative"))?; Prevention
- Never store sentinel values like -1 in version fields.
- Validate version fields as non-negative at every writer.
- Audit v2 catalog contents with as_u64 before running the migration.
- Keep catalog-writing tooling on current, validated schemas.
When it happens
Trigger: Running the v2->v3 migration when a node entry in the v2 catalog has `row_delete_predicate_version` that is negative or otherwise unrepresentable as u64 (e.g. i64::MIN, corrupt value).
Common situations: Corrupted or hand-edited v2 catalog objects; test fixtures with sentinel values like -1; catalogs written by older builds with a differently-typed version field.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- generation duration overflows u64 nanoseconds
- duration not to overflow
- last cache size overflows u64
- v2 catalog should exist since checkpoint was found
- cannot fit duration into u64
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/43c2cb9df8f2a4d8.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_catalog/src/catalog/migrations/v3.rs:268
/// the Stopped state on apply.
fn from_v2(&self, batch: &mut RecordBatch) {
let registered_time_ns = match &self.state {
NodeStateSnapshot::Running { registered_time_ns } => *registered_time_ns,
NodeStateSnapshot::Stopped { .. } => 0,
};
batch.push(&RegisterNode {
node_catalog_id: self.node_catalog_id.get(),
node_id: self.node_id.to_string(),
instance_id: self.instance_id.to_string(),
registered_time_ns,
core_count: self.core_count,
mode: self.mode.iter().copied().map(Into::into).collect(),
process_uuid: [0u8; 16], // placeholder -- not preserved in v2
conn_info: self.conn_info.as_ref().map(|s| s.to_string()),
cli_params: self.cli_params.as_ref().map(|s| s.to_string()),
row_delete_predicate_version: u64::try_from(self.row_delete_predicate_version)
.expect("row_delete_predicate_version exceeds u64"),
// v2 has no concept of feature level:
feature_level: FeatureLevel::ZERO,
});
if let NodeStateSnapshot::Stopped { stopped_time_ns } = &self.state {
batch.push(&StopNode {
node_catalog_id: self.node_catalog_id.get(),
node_id: self.node_id.to_string(),
stopped_time_ns: *stopped_time_ns,
process_uuid: [0u8; 16], // placeholder -- not preserved in v2
});
}
}
}
impl FromV2 for DatabaseSnapshot {
fn from_v2(&self, batch: &mut RecordBatch) {
let db_id = self.id.get();View on GitHub (pinned to 06200ef96b)