apache/iceberg · error · RuntimeException

Metastore operation failed for

Error message

Metastore operation failed for %s

What it means

Thrown by defaultWarehouseLocation when the metastore getDatabase call fails with a generic TException while computing the default warehouse location for a table. The RuntimeException message names the table identifier and wraps the Thrift cause. It reflects a metastore communication or server-side failure during location resolution.

Solutions

  1. Check the wrapped cause for the concrete TException and address it (connectivity, protocol, auth).
  2. Verify HMS is reachable and healthy; retry the table operation with backoff.
  3. Align client thrift/protocol versions with the HMS server version.
Defensive patterns

Strategy: retry

Validate before calling

try (Socket s = new Socket(hmsHost, hmsPort)) { /* HMS reachable before table ops */ }

Try / catch

try {
  catalog.createTable(ident, schema);
} catch (RuntimeException e) {
  if (e.getCause() instanceof TException) { /* backoff and retry; check HMS health */ }
  throw e;
}

Prevention

When it happens

Trigger: defaultWarehouseLocation (invoked during table create/load) hitting TException: HMS connection loss, thrift incompatibility, metastore internal error.

Common situations: HMS outage or restart during table creation; stale thrift connections after idle period; authentication/authorization errors surfacing as TException.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/688712a0da233681. Report an issue: GitHub.

Appendix: source

Thrown at hive-metastore/src/main/java/org/apache/iceberg/hive/HiveCatalog.java:775

    // - Create meta files
    // - Create the metadata in HMS, and this way committing the changes

    // Create a new location based on the namespace / database if it is set on database level
    String tableLocation = LocationUtil.tableLocation(tableIdentifier, uniqueTableLocation);
    try {
      Database databaseData =
          clients.run(client -> client.getDatabase(tableIdentifier.namespace().levels()[0]));
      if (databaseData.getLocationUri() != null) {
        // If the database location is set use it as a base.
        String databaseLocation = LocationUtil.stripTrailingSlash(databaseData.getLocationUri());
        return String.format("%s/%s", databaseLocation, tableLocation);
      }

    } catch (NoSuchObjectException e) {
      throw new NoSuchNamespaceException(
          e, "Namespace does not exist: %s", tableIdentifier.namespace().levels()[0]);
    } catch (TException e) {
      throw new RuntimeException(
          String.format("Metastore operation failed for %s", tableIdentifier), e);

    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new RuntimeException("Interrupted during commit", e);
    }

    // Otherwise, stick to the {WAREHOUSE_DIR}/{DB_NAME}.db/{TABLE_NAME} path
    String databaseLocation = databaseLocation(tableIdentifier.namespace().levels()[0]);
    return String.format("%s/%s", databaseLocation, tableLocation);
  }

  private String databaseLocation(String databaseName) {
    String warehouseLocation = conf.get(HiveConf.ConfVars.METASTOREWAREHOUSE.varname);
    Preconditions.checkNotNull(
        warehouseLocation, "Warehouse location is not set: hive.metastore.warehouse.dir=null");
    warehouseLocation = LocationUtil.stripTrailingSlash(warehouseLocation);
    return String.format("%s/%s.db", warehouseLocation, databaseName);

View on GitHub (pinned to 86d9c8fc54)