{"record":{"id":"161ec61920e545ba","repo":"influxdata/influxdb","slug":"table-snapshot-persistence-task-failed-index-cache","errorCode":null,"errorMessage":"Table snapshot persistence task failed","messagePattern":"Table snapshot persistence task failed","errorType":"exception","errorClass":"TableIndexCacheError","httpStatus":null,"severity":"error","filePath":"influxdb3_write/src/table_index_cache.rs","lineNumber":60,"sourceCode":"    #[error(\"Object store operation failed\")]\n    ObjectStore(#[source] object_store::Error),\n\n    #[error(\"JSON serialization/deserialization failed\")]\n    Json(#[source] serde_json::Error),\n\n    #[error(\"TableIndex operation failed\")]\n    TableIndex(#[source] crate::table_index::TableIndexError),\n\n    #[error(\"Object meta is missing filename\")]\n    MissingFilename,\n\n    #[error(\"Failed to parse snapshot sequence number from filename\")]\n    InvalidSnapshotSequenceNumber,\n\n    #[error(\"Unexpected error\")]\n    Unexpected(#[source] anyhow::Error),\n\n    #[error(\"Table snapshot persistence task failed\")]\n    TableSnapshotPersistenceTaskFailed(#[source] tokio::task::JoinError),\n\n    #[error(\"Failed to list table indices from object store\")]\n    ListIndices(#[source] object_store::Error),\n\n    #[error(\"Failed to parse table index path from object store path\")]\n    TableIndexPath(#[source] crate::paths::PathError),\n\n    #[error(\"Failed to list table index snapshots from object store\")]\n    ListSnapshots(#[source] object_store::Error),\n\n    #[error(\"Failed to parse table index snapshot path from object store path\")]\n    TableIndexSnapshotPath(#[source] crate::paths::PathError),\n\n    #[error(\"Failed to update table index: join task failed\")]\n    UpdateTaskFailed(#[source] tokio::task::JoinError),\n\n    #[error(\"Failed to list object store metadata\")]","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_write/src/table_index_cache.rs#L42-L78","documentation":"TableIndexCacheError::TableSnapshotPersistenceTaskFailed wraps a tokio::task::JoinError raised when a spawned task that persists table index snapshots (or updates table indexes) panicked or was cancelled. The cache fans out per-snapshot work with a JoinSet; a JoinError means one of those worker tasks died rather than returning its Result.","triggerScenarios":"js.join_next() returns Err in split_persisted_snapshots_to_table_index_snapshots (mapped to TableSnapshotPersistenceTaskFailed at table_index_cache.rs:474) or in update_all_from_object_store worker sets — caused by a panic inside the spawned future (e.g. the unwrap() on semaphore acquire or a serde unwrap) or task cancellation at shutdown.","commonSituations":"A bug-triggered panic inside snapshot split/persist code (e.g. unwrap on malformed data), OOM killing a task, or server shutdown cancelling in-flight conversion tasks during startup.","solutions":["Check logs for a panic message from the spawned task; the JoinError's panic payload identifies the failing code path.","If the panic stems from unwrap on externally supplied data (snapshot bytes, marker JSON), fix or validate the offending file and report/patch the unwrap.","Re-run TableIndexCache::initialize after restart so the conversion re-processes any snapshots left unconverted by the panicked task.","Avoid shutting the node down during first-run snapshot conversion; let the migration complete before stopping."],"exampleFix":"// before: panic inside spawned task propagates as JoinError\nlet _permit = sem.acquire_owned().await.unwrap();\n// after: handle acquisition failure gracefully\nlet permit = sem.acquire_owned().await.map_err(|_| TableIndexCacheError::Unexpected(anyhow::anyhow!(\"semaphore closed\")))?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_join_cancelled(e: &tokio::task::JoinError) -> bool {\n    e.is_cancelled()\n}","tryCatchPattern":"match res.map_err(TableIndexCacheError::TableSnapshotPersistenceTaskFailed)? {\n    Err(TableIndexCacheError::TableSnapshotPersistenceTaskFailed(j)) if j.is_cancelled() => {\n        info!(\"shutdown during conversion; will resume on next start\");\n    }\n    other => other?,\n}","preventionTips":["Replace unwrap()/expect() inside spawned snapshot tasks with typed errors","Do not stop the server while first-run snapshot conversion is in progress","Monitor memory: OOM kills surface as JoinErrors","Check panic logs (panic payload) whenever this error appears"],"tags":["tokio","panic","concurrency","rust"],"backgroundTag":"thread-interrupted","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"}