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

  1. Confirm the table key exists on the ref (catalog.tableExists) before/after the concurrent operation.
  2. Re-load the catalog/table on the correct branch where the table still exists.
  3. 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.
  4. 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

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


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