apache/iceberg · error · NoSuchTableException

NoSuchTableException(from)

Error message

NoSuchTableException(from)

What it means

Spark's renameTable failed because the source table identifier could not be loaded by the underlying Iceberg catalog; the Iceberg NoSuchTableException was caught and rethrown as Spark's NoSuchTableException for the 'from' identifier. Renaming requires the source table to exist and be loadable at commit time.

Source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:430

  }

  private boolean catalogDropTable(Identifier ident) {
    if (isPathIdentifier(ident)) {
      return tables.dropTable(((PathIdentifier) ident).location(), false /* don't purge data */);
    } else {
      return icebergCatalog.dropTable(buildIdentifier(ident), false /* don't purge data */);
    }
  }

  @Override
  public void renameTable(Identifier from, Identifier to)
      throws NoSuchTableException, TableAlreadyExistsException {
    try {
      checkNotPathIdentifier(from, "renameTable");
      checkNotPathIdentifier(to, "renameTable");
      icebergCatalog.renameTable(buildIdentifier(from), buildIdentifier(to));
    } catch (org.apache.iceberg.exceptions.NoSuchTableException e) {
      throw new NoSuchTableException(from);
    } catch (AlreadyExistsException e) {
      throw new TableAlreadyExistsException(to);
    }
  }

  @Override
  public void invalidateTable(Identifier ident) {
    if (!isPathIdentifier(ident)) {
      icebergCatalog.invalidateTable(buildIdentifier(ident));
    }
  }

  @Override
  public Identifier[] listTables(String[] namespace) {
    return icebergCatalog.listTables(Namespace.of(namespace)).stream()
        .map(ident -> Identifier.of(ident.namespace().levels(), ident.name()))
        .toArray(Identifier[]::new);
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Confirm the source table exists and is loadable via SELECT before renaming.
  2. Use the fully-qualified source name (catalog.namespace.table) to avoid resolution against the wrong catalog.
  3. Check for concurrent drops; coordinate rename with other jobs.
  4. If the metastore entry exists but loading fails, repair or re-register the table metadata location.

Example fix

// before
spark.sql("ALTER TABLE mydb.orders RENAME TO mydb.orders_v2") // NoSuchTableException: mydb.orders

// after
if (spark.catalog().tableExists("iceberg_catalog.mydb.orders")) {
  spark.sql("ALTER TABLE iceberg_catalog.mydb.orders RENAME TO iceberg_catalog.mydb.orders_v2")
} else {
  // handle missing source explicitly
}
Defensive patterns

Strategy: validation

Validate before calling

if (!spark.catalog().tableExists("iceberg_catalog.mydb.orders")) {
  throw new IllegalStateException("Rename source table does not exist");
}

Try / catch

try {
  catalog.renameTable(from, to);
} catch (NoSuchTableException e) {
  // source missing: report e.getMessage() with the resolved identifier
}

Prevention

When it happens

Trigger: Calling ALTER TABLE ... RENAME TO (or catalog.renameTable(from, to)) where buildIdentifier(from) does not resolve to an existing Iceberg table; the source was dropped concurrently; the 'from' identifier is qualified with the wrong catalog or namespace.

Common situations: Scripting RENAME operations where an earlier cleanup step already dropped the table; Hive-metastore-backed catalogs where the Hive table exists but the Iceberg metadata location is gone; passing an unqualified name while the table lives in another namespace.

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