apache/iceberg · error · NoSuchTableException
No such table '%s' in '%s'
Error message
No such table '%s' in '%s'
What it means
During NessieTableOperations.doRefresh, content lookup for the table key returned null while the operations instance already had loaded metadata (currentMetadataLocation() != null). This means the table existed previously but was deleted on the current ref, so NessieTableOperations throws NoSuchTableException naming the key and reference. The null is tolerated only when the table was never loaded.
Source
Thrown at nessie/src/main/java/org/apache/iceberg/nessie/NessieTableOperations.java:86
@Override
protected void doRefresh() {
try {
client.refresh();
} catch (NessieNotFoundException e) {
throw new UncheckedIOException(
String.format(
"Failed to refresh as ref '%s' is no longer valid.", client.getRef().getName()),
e);
}
String metadataLocation = null;
Reference reference = client.getRef().getReference();
try {
Content content = client.getApi().getContent().key(key).reference(reference).get().get(key);
LOG.debug("Content '{}' at '{}': {}", key, reference, content);
if (content == null) {
if (currentMetadataLocation() != null) {
throw new NoSuchTableException("No such table '%s' in '%s'", key, reference);
}
} else {
this.table =
content
.unwrap(IcebergTable.class)
.orElseThrow(() -> new NessieContentNotFoundException(key, reference.getName()));
metadataLocation = table.getMetadataLocation();
}
} catch (NessieNotFoundException ex) {
if (currentMetadataLocation() != null) {
throw new NoSuchTableException(ex, "No such table '%s'", key);
}
}
refreshFromMetadataLocation(
metadataLocation,
null,
2,
location ->View on GitHub (pinned to 86d9c8fc54)
Solutions
- Confirm the table key exists on the ref (catalog.tableExists) before/after the concurrent operation.
- Re-load the catalog/table on the correct branch where the table still exists.
- If the drop was unintended, restore the key by committing the previous IcebergTable content back to Nessie or resetting the branch to a prior hash.
- Coordinate drop/refresh jobs so tables aren't deleted mid-use.
Example fix
// before
Table t = catalog.loadTable(id); // refresh later fails: dropped concurrently
// after
if (catalog.tableExists(id)) {
Table t = catalog.loadTable(id);
// use t quickly, or re-check existence before each refresh
} Defensive patterns
Strategy: validation
Validate before calling
if (!catalog.tableExists(key)) { throw new IllegalStateException("Table dropped on ref " + catalog.getRef().getName()); } Try / catch
try { table.refresh(); } catch (NoSuchTableException e) { table = catalog.loadTable(key); } Prevention
- Coordinate drop operations with readers/streams
- Re-check existence before refresh in long-running jobs
- Use Nessie tags for stable reads of tables that may be dropped on branches
When it happens
Trigger: Refreshing a loaded table after it was dropped on the same branch; a concurrent drop committed between operations; reading through a ref where another process deleted the key.
Common situations: Long-running streaming query refreshing a table another job dropped; mistaken drop on the wrong branch; snapshot-style tag lookups where key was removed.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Table does not exist: %s
- No such table '%s'
- Cannot find Glue table %s after refresh, maybe another proce
- Table does not exist: %s
- View does not exist: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/140175792d887d81.
Report an issue: GitHub.