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
- Verify the source table exists with catalog.tableExists(from) before renaming
- Check the exact table identifier (namespace and name, including case)
- Confirm the catalog configuration points at the correct database/warehouse
- 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
- Check tableExists(from) before every rename
- Make rename operations idempotent (retry-safe) in job code
- Use consistent table identifiers from a shared constants/source of truth
- Watch for concurrent drops/renames from other jobs
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
- View does not exist
- Table does not exist: %s
- Cannot rename %s to %s. View does not exist
- Namespace does not exist: %s
- Cannot rename %s to %s. Table already exists
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9e5f7292774f2295.
Report an issue: GitHub.