apache/iceberg · error · NoSuchTableException
Failed to load table %s from catalog %s: dropped by another
Error message
Failed to load table %s from catalog %s: dropped by another process
What it means
A NoSuchTableException signalling the table's metadata row disappeared from the JDBC catalog between operations. doRefresh() found an empty result but a metadata location was previously cached, meaning the table was deleted by another process. This prevents operations against a stale table reference.
Source
Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcTableOperations.java:85
@Override
public void doRefresh() {
Map<String, String> table;
try {
table = JdbcUtil.loadTable(schemaVersion, connections, catalogName, tableIdentifier);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UncheckedInterruptedException(e, "Interrupted during refresh");
} catch (SQLException e) {
// SQL exception happened when getting table from catalog
throw new UncheckedSQLException(
e, "Failed to get table %s from catalog %s", tableIdentifier, catalogName);
}
if (table.isEmpty()) {
if (currentMetadataLocation() != null) {
throw new NoSuchTableException(
"Failed to load table %s from catalog %s: dropped by another process",
tableIdentifier, catalogName);
} else {
this.disableRefresh();
return;
}
}
String newMetadataLocation = table.get(METADATA_LOCATION_PROP);
Preconditions.checkState(
newMetadataLocation != null,
"Invalid table %s: metadata location is null",
tableIdentifier);
refreshFromMetadataLocation(newMetadataLocation);
}
@Override
public void doCommit(TableMetadata base, TableMetadata metadata) {View on GitHub (pinned to 86d9c8fc54)
Solutions
- Re-open the table via the catalog instead of continuing with the stale reference.
- Coordinate table lifecycle across processes (don't drop tables under active writers).
- Use catalog-level DROP TABLE rather than deleting catalog rows manually.
- Add application logic to catch NoSuchTableException and handle table recreation.
Example fix
// before
Table table = catalog.loadTable(identifier);
table.refresh(); // may throw if dropped elsewhere
// after
try {
table.refresh();
} catch (NoSuchTableException e) {
table = catalog.loadTable(identifier); // reload or handle missing table
} Defensive patterns
Strategy: try-catch
Validate before calling
// check the table still exists before committing
if (!catalog.tableExists(identifier)) {
throw new IllegalStateException("Table " + identifier + " no longer exists in catalog");
} Try / catch
try {
table.refresh();
} catch (org.apache.iceberg.exceptions.NoSuchTableException e) {
// table dropped by another process: stop writes, reload or recreate
table = catalog.tableExists(identifier) ? catalog.loadTable(identifier) : null;
} Prevention
- Never drop tables while other processes hold active references.
- Use catalog DROP TABLE, never manual DELETE on catalog rows.
- Coordinate table lifecycle with job scheduling/locks.
When it happens
Trigger: doRefresh() calls JdbcUtil.loadTable and gets an empty map while currentMetadataLocation() != null — i.e., the cached table was dropped externally.
Common situations: Two jobs/processes sharing a catalog where one drops the table the other is still writing to, manual DELETE from the catalog DB, DROP TABLE issued concurrently with commits.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Interrupted in call to initialize
- Interrupted in SQL command
- Interrupted in SQL query
- Failed to insert: %d of %d succeeded
- Failed to update: %d of %d succeeded
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/cd02445a81959872.
Report an issue: GitHub.