apache/iceberg · error · org.apache.iceberg.exceptions.NoSuchTableException

Cannot find source table

Error message

Cannot find source table %s

What it means

MigrateTableSparkAction first renames the source table to a backup identifier before creating the new Iceberg table in its place. If destCatalog().renameTable throws Spark's NoSuchTableException (the source vanished between load and rename), it is converted into Iceberg's NoSuchTableException with this message.

Solutions

  1. Verify the source table still exists: SHOW TABLES / DESCRIBE the identifier
  2. Re-run the MIGRATE procedure once no concurrent jobs touch the source table
  3. Check that the identifier resolves against the intended catalog (spark_catalog for the legacy source)

Example fix

// before
CALL iceberg.system.migrate('db.src_tbl') -- src_tbl dropped concurrently
// after
SHOW TABLES IN db; -- confirm src_tbl exists
CALL iceberg.system.migrate('db.src_tbl');
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the source exists and is quiescent before migrating
spark.sql("DESCRIBE TABLE db.src_tbl");

Try / catch

try { migrateAction.execute(); } catch (NoSuchTableException e) { /* source disappeared: verify identifier, re-create or re-run when stable */ }

Prevention

When it happens

Trigger: Calling MIGRATE and the source table is dropped by another session between action initialization and renameAndBackupSourceTable; wrong source identifier resolution in the destination catalog.

Common situations: Concurrent drop/overwrite of the source table; case-sensitive identifier mismatch causing renameTable to resolve a different catalog; a failed earlier migrate run left inconsistent catalog state.

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

Appendix: source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/actions/MigrateTableSparkAction.java:239

  @Override
  protected TableCatalog checkSourceCatalog(CatalogPlugin catalog) {
    // currently the import code relies on being able to look up the table in the session catalog
    Preconditions.checkArgument(
        catalog instanceof SparkSessionCatalog,
        "Cannot migrate a table from a non-Iceberg Spark Session Catalog. Found %s of class %s as the source catalog.",
        catalog.name(),
        catalog.getClass().getName());

    return (TableCatalog) catalog;
  }

  private void renameAndBackupSourceTable() {
    try {
      LOG.info("Renaming {} as {} for backup", sourceTableIdent(), backupIdent);
      destCatalog().renameTable(sourceTableIdent(), backupIdent);

    } catch (org.apache.spark.sql.catalyst.analysis.NoSuchTableException e) {
      throw new NoSuchTableException("Cannot find source table %s", sourceTableIdent());

    } catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {
      throw new AlreadyExistsException(
          "Cannot rename %s as %s for backup. The backup table already exists.",
          sourceTableIdent(), backupIdent);
    }
  }

  private void restoreSourceTable() {
    try {
      LOG.info("Restoring {} from {}", sourceTableIdent(), backupIdent);
      destCatalog().renameTable(backupIdent, sourceTableIdent());

    } catch (org.apache.spark.sql.catalyst.analysis.NoSuchTableException e) {
      LOG.error(
          "Cannot restore the original table, the backup table {} cannot be found", backupIdent, e);

    } catch (org.apache.spark.sql.catalyst.analysis.TableAlreadyExistsException e) {

View on GitHub (pinned to 86d9c8fc54)