influxdata/influxdb · error
database should exist by id
Error message
database should exist by id
What it means
Panic from `.expect("database should exist by id")` on `inner.databases.get_by_id(&self.database_schema.id)` inside the commit path of a CatalogTransaction (after `apply_catalog_batch` succeeds in versions/v2/update.rs). The code assumes that a successfully applied batch referencing this database leaves the database present in the catalog's databases map; a None result means the apply silently dropped or failed to register the database — an unrecoverable internal inconsistency.
Solutions
- Check the catalog log for a delete-database op with a sequence number between the transaction's start and commit; re-order or drop the conflicting transaction.
- Verify apply_catalog_batch's handling of database upserts for this sequence range; patch or upgrade to a version fixing the replay bug.
- Restore the catalog from a snapshot that still contains the database.
- Capture the sequence numbers and failing batch and file an upstream issue — this indicates a serious catalog consistency bug.
Example fix
// before
inner.apply_catalog_batch(&catalog_batch, sequence, None).map(|_| {
inner.databases.get_by_id(&self.database_schema.id).expect("database should exist by id")
})
// after
inner.apply_catalog_batch(&catalog_batch, sequence, None).and_then(|_| {
inner.databases.get_by_id(&self.database_schema.id)
.ok_or_else(|| Error::DatabaseMissingAfterCommit { id: self.database_schema.id })
}) Defensive patterns
Strategy: try-catch
Validate before calling
// Before committing, confirm the database still exists in the catalog
if catalog.databases().get_by_id(&db_schema.id).is_none() {
return Err("database was dropped; aborting stale transaction");
} Try / catch
// Wrap commit and handle the panic via catch_unwind at the replay boundary
let result = std::panic::catch_unwind(AssertUnwindSafe(|| tx.commit()));
match result {
Ok(Ok(db)) => Ok(db),
Ok(Err(e)) => Err(e),
Err(_panic) => Err("catalog consistency failure during commit; restore from snapshot".into()),
} Prevention
- Serialize database drop and write transactions; never run both concurrently.
- Track sequence numbers so a pending transaction is aborted if a drop-database op lands first.
- Restore catalogs only from snapshots where the referenced database exists.
- Monitor for this panic in replay code paths — it indicates a serious consistency bug to report upstream.
When it happens
Trigger: Committing a database-scoped catalog transaction (write_database / commit) where apply_catalog_batch succeeds but the databases map lacks `self.database_schema.id` — e.g. the batch deleted the database, applied ops out of order, or the database creation op was filtered out during replay.
Common situations: Catalog replay where a DROP DATABASE op precedes a pending transaction's ops; snapshots restored with the database missing; concurrent commits where one deletes while another commits writes; bugs in apply_catalog_batch's upsert logic.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- field family name exists
- auto field family exists
- column id in series key should be valid
- field does not exist
- field family ID and name don't exist
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/de31079cf8a30025.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_catalog/src/catalog/versions/v2/update.rs:1858
impl DatabaseCatalogTransaction {
pub fn sequence_number(&self) -> CatalogSequenceNumber {
self.catalog_sequence
}
/// Apply the current transaction to the [super::InnerCatalog] and return the updated [DatabaseSchema].
///
/// # NOTE
///
/// Used for testing purposes.
pub fn apply_to_inner(&self, inner: &mut super::InnerCatalog) -> Result<Arc<DatabaseSchema>> {
let (catalog_batch, sequence) = self.clone().catalog_batch();
inner
.apply_catalog_batch(&catalog_batch, sequence, None)
.map(|_| {
inner
.databases
.get_by_id(&self.database_schema.id)
.expect("database should exist by id")
})
}
/// Check if the transaction is empty, meaning it has no pending operations.
fn is_empty(&self) -> bool {
self.ops.is_empty()
&& self.tables.resource_iter().all(|tx| {
tx.column_definitions.is_empty() && tx.field_family_definitions.is_empty()
})
}
fn catalog_batch(self) -> (CatalogBatch, CatalogSequenceNumber) {
let s = self.catalog_sequence;
(self.into(), s)
}
/// Check if a table exists by its name in the current transaction or in the database schema.
fn table_exists_by_name(&self, name: &str) -> bool {View on GitHub (pinned to 06200ef96b)