influxdata/influxdb · error · TableIndexCacheError

Failed to delete table index

Error message

Failed to delete table index {table_id} from object store

What it means

TableIndexCacheError::DeleteTableIndex is thrown when deleting the table index object itself from the object store fails. It carries the table_id and wraps an object_store::Error. This occurs during table purge/drop when the final index blob cannot be removed, leaving the table index potentially orphaned in storage.

Solutions

  1. Check the wrapped object_store::Error and the table_id to find the exact blob and failure cause.
  2. Verify IAM delete permissions on the table index prefix in the bucket.
  3. Retry the delete; if the blob is versioned/locked, disable or override the retention policy.
  4. Manually clean up the orphaned index object after fixing the underlying cause.

Example fix

// before
cache.delete_table_index(table_id).await?;
// after
if let Err(e) = cache.delete_table_index(table_id).await {
  log::error!("orphaned index possible for {table_id:?}: {e}");
  schedule_orphan_cleanup(table_id);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: confirm the index object exists and is deletable before dropping
let exists = object_store.head(&index_path).await.is_ok();
let can_delete = iam_allows_delete(&index_path);
assert!(exists && can_delete, "cannot delete index blob {index_path}");

Type guard

fn is_delete_index_err(e: &TableIndexCacheError) -> Option<(TableIndexId, &object_store::Error)> {
  if let TableIndexCacheError::DeleteTableIndex { table_id, source } = e {
    Some((*table_id, source))
  } else { None }
}

Try / catch

match cache.delete_table_index(table_id).await {
  Err(TableIndexCacheError::DeleteTableIndex { table_id, source }) => {
    log::error!("index delete failed for {table_id:?}: {source}; scheduling orphan cleanup");
    orphan_queue.push(table_id);
  }
  Err(e) => return Err(e),
  Ok(()) => {}
}

Prevention

When it happens

Trigger: purge_table / DROP TABLE flows in table_index_cache.rs calling object_store delete on the table index blob, where the store returns an error (permission, network, or store-side failure).

Common situations: Service account missing delete rights on the index prefix; object-lock/retention policies protecting index blobs; object store outage or throttling during table drops; repeated drops racing with snapshot persistence.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/63c7e76c65007a68. Report an issue: GitHub.

Appendix: source

Thrown at influxdb3_write/src/table_index_cache.rs:112

    SplitPersistedSnapshotError(#[source] crate::table_index::TableIndexError),

    #[error("Failed to load table index from object store")]
    LoadTableIndexFromObjectStoreError(#[source] crate::table_index::TableIndexError),

    #[error("Failed to update table index from object store")]
    UpdateTableIndexFromObjectStoreError(#[source] crate::table_index::TableIndexError),

    #[error("Failed to create table index from object store")]
    CreateTableIndexFromObjectStoreError(#[source] crate::table_index::TableIndexError),

    #[error("Failed to delete parquet file {path} from object store")]
    DeleteParquetFile {
        path: String,
        #[source]
        source: object_store::Error,
    },

    #[error("Failed to delete table index {table_id} from object store")]
    DeleteTableIndex {
        table_id: TableIndexId,
        #[source]
        source: object_store::Error,
    },
}

pub type Result<T> = std::result::Result<T, TableIndexCacheError>;

/// Configuration for the TableIndexCache
#[derive(Debug, Clone, Copy)]
pub struct TableIndexCacheConfig {
    /// Maximum number of entries to cache (None = unlimited)
    pub max_entries: Option<usize>,
    /// Limit the concurrency of cache <-> object store operations.
    pub concurrency_limit: usize,
}

View on GitHub (pinned to 06200ef96b)