apache/iceberg · error · NoSuchTableException

Table not found: ${ident}

Error message

Table not found: ${ident}

What it means

loadTable on SparkRewriteTableCatalog looks up the table only in the in-memory SparkTableCache keyed by the identifier name; when the groupId is absent from the cache it throws NoSuchTableException for the identifier. It never consults a real catalog.

Source

Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/SparkRewriteTableCatalog.java:53

  private static final String CLASS_NAME = SparkRewriteTableCatalog.class.getName();
  private static final SparkTableCache TABLE_CACHE = SparkTableCache.get();

  private String name = null;

  @Override
  public Identifier[] listTables(String[] namespace) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support listing tables");
  }

  @Override
  public SparkRewriteTable loadTable(Identifier ident) throws NoSuchTableException {
    validateNoNamespace(ident);

    String groupId = ident.name();
    Table table = TABLE_CACHE.get(groupId);

    if (table == null) {
      throw new NoSuchTableException(ident);
    }

    return new SparkRewriteTable(table, groupId);
  }

  @Override
  public SparkTable loadTable(Identifier ident, String version) throws NoSuchTableException {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support time travel");
  }

  @Override
  public SparkTable loadTable(Identifier ident, long timestampMicros) throws NoSuchTableException {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support time travel");
  }

  @Override
  public void invalidateTable(Identifier ident) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support table invalidation");

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Load the table through the proper catalog (SparkCatalog) rather than SparkRewriteTableCatalog.
  2. Only use the rewrite catalog within the Spark rewrite procedures that populate the cache.
  3. Verify the identifier name matches the groupId the rewrite procedure registered in SparkTableCache.
  4. Re-run the rewrite procedure if its cache entry was evicted.

Example fix

// before
SparkRewriteTable t = (SparkRewriteTable) rewriteCatalog.loadTable(ident);
// after
SparkTable t = (SparkTable) sparkCatalog.loadTable(ident); // use the real catalog for direct loads
Defensive patterns

Strategy: try-catch

Validate before calling

String groupId = ident.name();
if (!sparkTableCache.contains(groupId)) {
  throw new IllegalStateException("groupId not in SparkTableCache: " + groupId);
}

Try / catch

try {
  Table t = rewriteCatalog.loadTable(ident);
} catch (NoSuchTableException e) {
  Table t = realCatalog.loadTable(ident); // fall back to the authoritative catalog
}

Prevention

When it happens

Trigger: Calling SparkRewriteTableCatalog.loadTable(ident) with an identifier whose name is not a groupId currently registered in SparkTableCache — e.g. loading the table outside a rewrite procedure, after the cache entry expired, or with a wrong/renamed identifier.

Common situations: Invoking loadTable on the rewrite catalog from application code instead of through the rewrite procedure; stale cache entries evicted between procedure stages; identifier mismatch between the procedure call and the cached entry.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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