apache/iceberg · error · NoSuchTableException

Table does not exist: %s

Error message

Table does not exist: %s

What it means

NoSuchTableException thrown by JdbcCatalog.renameTable when the source table does not exist in the iceberg_catalog table. The rename is rejected up-front via tableExists(from) so no rows are updated for a nonexistent source.

Source

Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcCatalog.java:361

    return fetch(
        row ->
            JdbcUtil.stringToTableIdentifier(
                row.getString(JdbcUtil.TABLE_NAMESPACE), row.getString(JdbcUtil.TABLE_NAME)),
        (schemaVersion == JdbcUtil.SchemaVersion.V1)
            ? JdbcUtil.V1_LIST_TABLE_SQL
            : JdbcUtil.V0_LIST_TABLE_SQL,
        catalogName,
        JdbcUtil.namespaceToString(namespace));
  }

  @Override
  public void renameTable(TableIdentifier from, TableIdentifier to) {
    if (from.equals(to)) {
      return;
    }

    if (!tableExists(from)) {
      throw new NoSuchTableException("Table does not exist: %s", from);
    }

    if (!namespaceExists(to.namespace())) {
      throw new NoSuchNamespaceException("Namespace does not exist: %s", to.namespace());
    }

    if (schemaVersion == JdbcUtil.SchemaVersion.V1 && viewExists(to)) {
      throw new AlreadyExistsException("Cannot rename %s to %s. View already exists", from, to);
    }

    if (tableExists(to)) {
      throw new AlreadyExistsException("Table already exists: %s", to);
    }

    int updatedRecords =
        execute(
            err -> {
              if (JdbcUtil.isConstraintViolation(err)) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Verify the source table exists with catalog.tableExists(from) before renaming
  2. Check the exact table identifier (namespace and name, including case)
  3. Confirm the catalog configuration points at the correct database/warehouse
  4. If a prior rename partially succeeded, use the new name instead of retrying the old one

Example fix

// before
catalog.renameTable(TableIdentifier.of("db","events"), TableIdentifier.of("db","events_v2"));
// after
TableIdentifier from = TableIdentifier.of("db", "events");
if (catalog.tableExists(from)) {
  catalog.renameTable(from, TableIdentifier.of("db", "events_v2"));
}
Defensive patterns

Strategy: try-catch

Validate before calling

TableIdentifier from = TableIdentifier.of("db", "events");
if (!catalog.tableExists(from)) {
  throw new IllegalStateException("source table missing: " + from);
}

Type guard

boolean canRename(Catalog c, TableIdentifier from, TableIdentifier to) {
  return c.tableExists(from) && c.namespaceExists(to.namespace()) && !c.tableExists(to);
}

Try / catch

try {
  catalog.renameTable(from, to);
} catch (NoSuchTableException e) {
  LOG.warn("rename skipped, source gone: {}", from);
}

Prevention

When it happens

Trigger: Calling catalog.renameTable(from, to) where `from` was already dropped, was never created, is registered under a different name/case, or lives in a different catalog/database than the one being used.

Common situations: Double-rename or retry after a successful rename, typos in the fully-qualified table name, pointing the catalog at the wrong JDBC database, or app code assuming a table created by another job already exists.

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