apache/iceberg · error · AlreadyExistsException

View already exists: %s

Error message

View already exists: %s

What it means

AlreadyExistsException raised by JdbcViewOperations.doCommit when creating a NEW view (no current metadata location) hits a constraint violation in the catalog table — meaning a row for this view identifier already exists in iceberg_views. This is the create-vs-concurrent-create race detection: the INSERT's unique-key guard fired.

Source

Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcViewOperations.java:125

        updateView(newMetadataLocation, oldMetadataLocation);
      } else {
        // view does not exist, create it
        LOG.debug("Committing new view: {}", viewName());
        createView(newMetadataLocation);
      }

    } catch (SQLTimeoutException e) {
      throw new UncheckedSQLException(e, "Database Connection timeout");
    } catch (SQLTransientConnectionException | SQLNonTransientConnectionException e) {
      throw new UncheckedSQLException(e, "Database Connection failed");
    } catch (DataTruncation e) {
      throw new UncheckedSQLException(e, "Database data truncation error");
    } catch (SQLWarning e) {
      throw new UncheckedSQLException(e, "Database warning");
    } catch (SQLException e) {
      if (JdbcUtil.isConstraintViolation(e)) {
        if (currentMetadataLocation() == null) {
          throw new AlreadyExistsException(e, "View already exists: %s", viewIdentifier);
        } else {
          throw new UncheckedSQLException(e, "View already exists: %s", viewIdentifier);
        }
      }

      throw new UncheckedSQLException(e, "Unknown failure");
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new UncheckedInterruptedException(e, "Interrupted during commit");
    }
  }

  @Override
  protected String viewName() {
    return viewIdentifier.toString();
  }

  @Override

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check catalog.viewExists before creating, or handle AlreadyExistsException and reuse the existing view
  2. Use CREATE OR REPLACE semantics where appropriate for your workflow
  3. If the row is stale/corrupt (view was dropped but row remains), clean up the catalog row
  4. Serialize view creation for the same identifier in your orchestration

Example fix

// before
catalog.createView(ident, schema, spec, sql); // AlreadyExistsException on race
// after
if (!catalog.viewExists(ident)) {
  catalog.createView(ident, schema, spec, sql);
} else {
  View existing = catalog.loadView(ident); // reuse
}
Defensive patterns

Strategy: try-catch

Validate before calling

boolean exists = catalog.viewExists(ident);
if (exists) {
  throw new IllegalStateException("View already exists: " + ident);
}

Try / catch

try {
  catalog.createView(ident, schema, spec, sql);
} catch (AlreadyExistsException e) {
  // concurrent create won; load the existing view instead
  View existing = catalog.loadView(ident);
}

Prevention

When it happens

Trigger: CREATE VIEW on a name that already exists, or two sessions concurrently creating the same view — one insert succeeds, the other trips the primary-key/unique constraint and gets this exception.

Common situations: Race between two jobs both issuing CREATE VIEW IF NOT EXISTS-style logic, or a stale catalog client that didn't see the existing row during the pre-insert existence check.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/4d26965a619c4ab7. Report an issue: GitHub.