{"record":{"id":"f0e65ea80996fd53","repo":"influxdata/influxdb","slug":"failed-to-split-persisted-snapshot-into-table-snapshots","errorCode":null,"errorMessage":"Failed to split persisted snapshot into table snapshots","messagePattern":"Failed to split persisted snapshot into table snapshots","errorType":"exception","errorClass":"TableIndexCacheError","httpStatus":null,"severity":"error","filePath":"influxdb3_write/src/table_index_cache.rs","lineNumber":93,"sourceCode":"    #[error(\"Failed to update table index: join task failed\")]\n    UpdateTaskFailed(#[source] tokio::task::JoinError),\n\n    #[error(\"Failed to list object store metadata\")]\n    ListMetasError(#[source] object_store::Error),\n\n    #[error(\"Failed to load table index conversion marker bytes from object store\")]\n    LoadConversionMarkerBytesError(#[source] object_store::Error),\n\n    #[error(\"Failed to serialize initial table index conversion marker\")]\n    SerializeConversionMarkerError(#[source] serde_json::Error),\n\n    #[error(\"Failed to put initial table index conversion marker to object store\")]\n    PutConversionMarkerError(#[source] object_store::Error),\n\n    #[error(\"Failed to parse snapshot info file path\")]\n    ParseSnapshotPathError(#[source] anyhow::Error),\n\n    #[error(\"Failed to split persisted snapshot into table snapshots\")]\n    SplitPersistedSnapshotError(#[source] crate::table_index::TableIndexError),\n\n    #[error(\"Failed to load table index from object store\")]\n    LoadTableIndexFromObjectStoreError(#[source] crate::table_index::TableIndexError),\n\n    #[error(\"Failed to update table index from object store\")]\n    UpdateTableIndexFromObjectStoreError(#[source] crate::table_index::TableIndexError),\n\n    #[error(\"Failed to create table index from object store\")]\n    CreateTableIndexFromObjectStoreError(#[source] crate::table_index::TableIndexError),\n\n    #[error(\"Failed to delete parquet file {path} from object store\")]\n    DeleteParquetFile {\n        path: String,\n        #[source]\n        source: object_store::Error,\n    },\n","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_write/src/table_index_cache.rs#L75-L111","documentation":"TableIndexCacheError::SplitPersistedSnapshotError, thrown when splitting a persisted wal/snapshot into per-table snapshots fails inside the TableIndex layer (wrapping crate::table_index::TableIndexError). The cache converts one catalog snapshot into multiple TableIndexSnapshot objects; a structural problem in the snapshot data aborts the load.","triggerScenarios":"Loading a TableIndex from the object store: the persisted snapshot (parquet file list, table mappings, sequence numbers) is split per table; TableIndex methods like split_persisted_snapshot return TableIndexError when entries reference missing tables, sequence gaps, or malformed snapshot payloads.","commonSituations":"Snapshot JSON corrupted or truncated by an interrupted write/crash; data written by a newer InfluxDB 3 version then read by an older one (schema drift); object store objects manually copied out of order during restore.","solutions":["Inspect the inner TableIndexError (via #[source]) to find the specific snapshot field or entry that failed validation","Restore from a consistent backup or an earlier valid snapshot; ensure restores copy the full snapshot set atomically","Pin the reader to the same InfluxDB 3 version that wrote the snapshot, or upgrade to a version that reads the newer format","Delete/rebuild the affected table index from the WAL/parquet data using the recovery tooling, since snapshots are derived state"],"exampleFix":"// before: hard fail the whole cache init\nlet per_table = split_persisted_snapshot(&snap)?;\n// after: isolate the failure and fall back to reloading from source parquet\nmatch split_persisted_snapshot(&snap) {\n    Ok(per_table) => hydrate(per_table),\n    Err(e) => { error!(error=?e, \"snapshot split failed; rebuilding index\"); rebuild_index_from_parquet(db_id, table_id).await?; }\n}","handlingStrategy":"fallback","validationCode":"// validate snapshot payload before split\nfn snapshot_self_check(snap: &PersistedSnapshot) -> Result<(), String> {\n    if snap.parquet_files.is_empty() { return Err(\"empty snapshot\".into()); }\n    if snap.min_sequence_number > snap.max_sequence_number {\n        return Err(\"sequence range inverted\".into());\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(TableIndexCacheError::SplitPersistedSnapshotError(e)) => {\n        error!(source=?e, \"snapshot split failed; falling back to full index rebuild\");\n        rebuild_from_parquet().await?;\n    }\n    other => other?,\n}","preventionTips":["Take and restore backups atomically — never partially copy snapshot sets","Upgrade reader and writer to the same InfluxDB 3 version together","Verify checksums of snapshot files after restore","Keep WAL/parquet sources intact so indexes can always be rebuilt from scratch"],"tags":["snapshot","influxdb3","data-corruption"],"backgroundTag":"internal-invariant-violation","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}