apache/iceberg · error · RuntimeMetaException

Failed to start an embedded metastore because embedded…

Error message

Failed to start an embedded metastore because embedded Derby supports only one client at a time. To fix this, use a metastore that supports multiple clients.

What it means

HiveClientPool.newClient() detects the Derby message 'Another instance of Derby may have already booted' and raises a dedicated RuntimeMetaException explaining that an embedded Derby metastore allows only one client at a time. It occurs in local/dev setups where multiple clients share one embedded Derby database.

Solutions

  1. Point hive.metastore.uris at a real (remote) metastore service instead of using an embedded one — this is the fix the message itself recommends.
  2. Stop the other process holding the Derby lock, or remove stale Derby lck/db files from the metastore directory after confirming nothing is running.
  3. Ensure only one embedded-metastore client runs at a time (serialize tests, use testcontainers with a dedicated metastore per worker).
  4. Use a shared test metastore (e.g., a Dockerized Postgres-backed Hive metastore) for parallel test runs.

Example fix

// before
conf.set("hive.metastore.uris", ""); // embedded metastore, Derby-locked
// after
conf.set("hive.metastore.uris", "thrift://localhost:9083"); // run metastore service
HiveCatalog catalog = new HiveCatalog();
catalog.setConf(conf);
Defensive patterns

Strategy: validation

Validate before calling

// detect embedded-metastore usage before connecting
if (conf.get("hive.metastore.uris") == null || conf.get("hive.metastore.uris").isEmpty()) {
  throw new IllegalStateException("Embedded metastore (Derby) not safe for multi-client use; set hive.metastore.uris");
}

Try / catch

try {
  catalog.initialize("hive", conf);
} catch (RuntimeMetaException e) {
  if (e.getMessage().contains("embedded Derby")) {
    // stop competing client or switch to remote metastore, then retry
  }
}

Prevention

When it happens

Trigger: Two or more processes (or two HiveCatalog instances in one JVM with separate client pools) opening an embedded metastore backed by the same Derby data directory; the second client's newClient() sees the Derby boot-conflict MetaException.

Common situations: Local testing where a unit test JVM and a Spark shell both use an embedded metastore; a previous test JVM crashed leaving the Derby lock; running multiple workers against a dev config that never pointed at a real remote metastore.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

Thrown at hive-metastore/src/main/java/org/apache/iceberg/hive/HiveClientPool.java:78

  protected IMetaStoreClient newClient() {
    try {
      try {
        return GET_CLIENT.invoke(
            hiveConf, (HiveMetaHookLoader) tbl -> null, HiveMetaStoreClient.class.getName());
      } catch (RuntimeException e) {
        // any MetaException would be wrapped into RuntimeException during reflection, so let's
        // double-check type here
        if (e.getCause() instanceof MetaException) {
          throw (MetaException) e.getCause();
        }
        throw e;
      }
    } catch (MetaException e) {
      throw new RuntimeMetaException(e, "Failed to connect to Hive Metastore");
    } catch (Throwable t) {
      if (t.getMessage() != null
          && t.getMessage().contains("Another instance of Derby may have already booted")) {
        throw new RuntimeMetaException(
            t,
            "Failed to start an embedded metastore because embedded "
                + "Derby supports only one client at a time. To fix this, use a metastore that supports "
                + "multiple clients.");
      }

      throw new RuntimeMetaException(t, "Failed to connect to Hive Metastore");
    }
  }

  @Override
  protected IMetaStoreClient reconnect(IMetaStoreClient client) {
    try {
      client.close();
      client.reconnect();
    } catch (MetaException e) {
      throw new RuntimeMetaException(e, "Failed to reconnect to Hive Metastore");
    }

View on GitHub (pinned to 86d9c8fc54)