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
- Point hive.metastore.uris at a real (remote) metastore service instead of using an embedded one — this is the fix the message itself recommends.
- Stop the other process holding the Derby lock, or remove stale Derby lck/db files from the metastore directory after confirming nothing is running.
- Ensure only one embedded-metastore client runs at a time (serialize tests, use testcontainers with a dedicated metastore per worker).
- 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
- Always set hive.metastore.uris to a real metastore for anything beyond a single local client
- Run test suites against a shared remote/containerized metastore, not embedded Derby
- Clean up stale Derby lock files after crashed local test JVMs
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
- Cannot call acquireLock twice for
- Could not acquire the lock on
- Could not find lock with HMSClient
- Error generating host name
- Failed to acquire locks from metastore because the…
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)