databendlabs/databend · error

not implemented

Error message

not implemented

What it means

The Iceberg catalog's `list_databases_history` is an explicit `unimplemented!()` stub. Iceberg catalogs do not expose database drop/undo history, so calling this catalog API panics with 'not implemented'.

Solutions

  1. Do not run database-history queries against Iceberg catalogs; use `SHOW DATABASES` instead
  2. Add an early check in the query layer that returns a clear 'not supported for iceberg catalog' ErrorCode instead of panicking
  3. Implement the method by delegating to the underlying iceberg catalog's history API if it gains one

Example fix

// caller side
if catalog.engine() == "iceberg" {
    return Err(ErrorCode::Unsupported(format!("list_databases_history for iceberg catalog {}", name)));
}
let dbs = catalog.list_databases_history(&tenant).await?;
Defensive patterns

Strategy: validation

Validate before calling

let supports_history = catalog.as_any().downcast_ref::<IcebergCatalog>().is_none();
if !supports_history { return Err("SHOW DATABASES HISTORY unsupported for iceberg".into()); }

Type guard

fn is_iceberg_catalog(c: &dyn Catalog) -> bool { c.as_any().downcast_ref::<IcebergCatalog>().is_some() }

Try / catch

match std::panic::catch_unwind(AssertUnwindSafe(|| rt.block_on(catalog.list_databases_history(&tenant)))) {
    Ok(Ok(dbs)) => dbs,
    _ => catalog.list_databases(&tenant).await?, // fallback to current listing
}

Prevention

When it happens

Trigger: Executing `SHOW DATABASES HISTORY` (or any MetaAPI path that calls `list_databases_history`) against a catalog of the Iceberg engine.

Common situations: A user runs history/undo queries on an Iceberg-backed database expecting the same behavior as native catalogs; tooling enumerates catalog features generically and hits the stub.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/c59166e43e9d4beb. Report an issue: GitHub.

Appendix: source

Thrown at src/query/storages/iceberg/src/catalog.rs:328

        true
    }

    fn disable_table_info_refresh(self: Arc<Self>) -> Result<Arc<dyn Catalog>> {
        Ok(self)
    }

    #[fastrace::trace]
    #[async_backtrace::framed]
    async fn get_database(&self, tenant: &Tenant, db_name: &str) -> Result<Arc<dyn Database>> {
        let c = self.exists_database(tenant, db_name).await?;
        if !c {
            return Err(ErrorCode::UnknownDatabase(db_name.to_string()));
        }
        Ok(Arc::new(IcebergDatabase::create(self.clone(), db_name)))
    }

    async fn list_databases_history(&self, _tenant: &Tenant) -> Result<Vec<Arc<dyn Database>>> {
        unimplemented!()
    }

    #[async_backtrace::framed]
    async fn list_databases(&self, _tenant: &Tenant) -> Result<Vec<Arc<dyn Database>>> {
        let db_names = self
            .iceberg_catalog()
            .list_namespaces(None)
            .await
            .map_err(|err| {
                ErrorCode::Internal(format!("Iceberg catalog load database failed: {err:?}"))
            })?;
        let mut dbs = Vec::new();
        for db_name in db_names {
            let db = Arc::new(IcebergDatabase::create(
                self.clone(),
                &db_name.to_url_string(),
            )) as Arc<dyn Database>;
            dbs.push(db);

View on GitHub (pinned to 288d84d76e)