apache/iceberg · error · ViewAlreadyExistsException

ViewAlreadyExistsException(ident)

Error message

ViewAlreadyExistsException(ident)

What it means

When createView's underlying ViewBuilder .create() fails with Iceberg's AlreadyExistsException, it is converted to Spark's ViewAlreadyExistsException for the identifier. The view with that exact name already exists in the catalog and plain CREATE VIEW refuses to overwrite it.

Source

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

                .putAll(Spark3Util.rebuildCreateProperties(properties))
                .put(SparkView.QUERY_COLUMN_NAMES, COMMA_JOINER.join(queryColumnNames))
                .buildKeepingLast();

        org.apache.iceberg.view.View view =
            asViewCatalog
                .buildView(buildIdentifier(ident))
                .withDefaultCatalog(currentCatalog)
                .withDefaultNamespace(Namespace.of(currentNamespace))
                .withQuery("spark", sql)
                .withSchema(icebergSchema)
                .withLocation(properties.get("location"))
                .withProperties(props)
                .create();
        return new SparkView(catalogName, view);
      } catch (org.apache.iceberg.exceptions.NoSuchNamespaceException e) {
        throw new NoSuchNamespaceException(currentNamespace);
      } catch (AlreadyExistsException e) {
        throw new ViewAlreadyExistsException(ident);
      }
    }

    throw new UnsupportedOperationException(
        "Creating a view is not supported by catalog: " + catalogName);
  }

  @Override
  public View replaceView(
      Identifier ident,
      String sql,
      String currentCatalog,
      String[] currentNamespace,
      StructType schema,
      String[] queryColumnNames,
      String[] columnAliases,
      String[] columnComments,
      Map<String, String> properties)

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use CREATE VIEW IF NOT EXISTS (or CREATE OR REPLACE VIEW) to make the statement idempotent
  2. Drop the existing view first if replacement is intended: DROP VIEW catalog.db.name then recreate
  3. Pick a different view name if the existing object is intentional
  4. Handle ViewAlreadyExistsException in code and treat it as success when creation is best-effort

Example fix

// before
CREATE VIEW prod.analytics.daily_summary AS SELECT ...;
// after
CREATE VIEW IF NOT EXISTS prod.analytics.daily_summary AS SELECT ...;
// or: CREATE OR REPLACE VIEW prod.analytics.daily_summary AS SELECT ...;
Defensive patterns

Strategy: validation

Validate before calling

boolean exists = spark.sql("SHOW VIEWS IN " + db).collectAsList().stream()
    .anyMatch(r -> r.getString(0).equalsIgnoreCase(name));
// choose IF NOT EXISTS vs CREATE OR REPLACE based on `exists` and intent

Try / catch

try {
  spark.sql("CREATE VIEW " + ident + " AS SELECT ...;");
} catch (org.apache.spark.sql.catalyst.analysis.ViewAlreadyExistsException e) {
  spark.sql("CREATE OR REPLACE VIEW " + ident + " AS SELECT ...;");
}

Prevention

When it happens

Trigger: CREATE VIEW catalog.db.name executed when a view (and in most catalogs also a table) with that identifier already exists; concurrent pipelines both attempting CREATE VIEW for the same name.

Common situations: Re-running non-idempotent migration/ETL scripts that create views; two jobs racing to create the same view; confusion between tables and views sharing the same name in the catalog; forgetting IF NOT EXISTS in DDL.

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