apache/iceberg · error · NoSuchTableException

NoSuchTableException(ident)

Error message

NoSuchTableException(ident)

What it means

Spark's NoSuchTableException thrown from the load path when the identifier has an empty namespace and the Iceberg catalog reports no table. Because there is no namespace to reinterpret as a table identifier (snapshot-selector fallback), Spark immediately surfaces the original failure as NoSuchTableException for the identifier.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:941

    if (identifier instanceof PathIdentifier) {
      throw new IllegalArgumentException(
          String.format(
              "Cannot pass path based identifier to %s method. %s is a path.", method, identifier));
    }
  }

  private Table load(Identifier ident, TimeTravel timeTravel) throws NoSuchTableException {
    if (isPathIdentifier(ident)) {
      return loadPath((PathIdentifier) ident, timeTravel);
    }

    try {
      org.apache.iceberg.Table table = icebergCatalog.loadTable(buildIdentifier(ident));
      return SparkTable.create(table, timeTravel);

    } catch (org.apache.iceberg.exceptions.NoSuchTableException e) {
      if (ident.namespace().length == 0) {
        throw new NoSuchTableException(ident);
      }

      // if the original load didn't work, try using the namespace as an identifier because
      // the original identifier may include a snapshot selector or may point to the changelog
      TableIdentifier namespaceAsIdent = buildIdentifier(namespaceToIdentifier(ident.namespace()));
      org.apache.iceberg.Table table;
      try {
        table = icebergCatalog.loadTable(namespaceAsIdent);
      } catch (Exception ignored) {
        // the namespace does not identify a table, so it cannot be a table with a snapshot selector
        // throw an exception for the original identifier
        throw new NoSuchTableException(ident);
      }

      // loading the namespace as a table worked, check the name to see if it is a valid selector
      // or if the name points to the changelog

      if (ident.name().equalsIgnoreCase(SparkChangelogTable.TABLE_NAME)) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Qualify the table with its namespace: USE db; or SELECT * FROM catalog.db.table
  2. Verify the table exists with SHOW TABLES IN catalog.db
  3. Check the spark.sql.catalog.<name> wiring points at the intended warehouse
  4. Set the session catalog/current namespace so single-part names resolve

Example fix

// before
SELECT * FROM local.events; // no namespace, table not found
// after
SELECT * FROM local.db.events;
Defensive patterns

Strategy: validation

Validate before calling

if (ident.namespace().length == 0 || !spark.catalog().tableExists(ident.namespace(), ident.name())) { /* qualify or fix the name */ }

Try / catch

try {
  Table t = catalog.loadTable(ident);
} catch (NoSuchTableException e) {
  // use a namespace-qualified identifier
}

Prevention

When it happens

Trigger: catalog.loadTable(Identifier of single name) where icebergCatalog.loadTable throws NoSuchTableException and ident.namespace().length == 0 — i.e., referencing just 'tablename' with no database and no such table at the catalog root.

Common situations: Forgetting the database/namespace qualifier; using the wrong catalog name in spark.sql.catalog config; table dropped or never created; current namespace not set in the session.

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/02e83bd493f3ac20. Report an issue: GitHub.