apache/iceberg · error · UnsupportedOperationException

Replacing a view is not supported by catalog: catalogName

Error message

Replacing a view is not supported by catalog: catalogName

What it means

SparkCatalog.replaceView throws UnsupportedOperationException when the wrapped catalog does not implement the Iceberg ViewCatalog interface (asViewCatalog is null). Since views cannot even be loaded by such a catalog, CREATE OR REPLACE VIEW cannot be executed, and the unsupported catalog name is reported.

Solutions

  1. Configure spark.sql.catalog.<name> with a ViewCatalog implementation (HiveCatalog, JdbcCatalog, RESTCatalog, NessieCatalog).
  2. Replace view-refresh logic with table-based flows (e.g. INSERT OVERWRITE into an Iceberg table) if stuck on a table-only catalog.
  3. Implement org.apache.iceberg.catalog.ViewCatalog in your custom catalog to support view replacement.
  4. Route view DDL to a different, view-capable catalog in the same session.

Example fix

// before
spark.conf.set("spark.sql.catalog.etl", "org.apache.iceberg.hadoop.HadoopCatalog");
spark.sql("CREATE OR REPLACE VIEW etl.ns.v AS SELECT ..."); // UnsupportedOperationException

// after
spark.conf.set("spark.sql.catalog.etl", "org.apache.iceberg.rest.RESTCatalog");
spark.sql("CREATE OR REPLACE VIEW etl.ns.v AS SELECT ...");
Defensive patterns

Strategy: validation

Validate before calling

Catalog catalog = Spark3Util.loadIcebergCatalog(spark, catalogName);
if (!(catalog instanceof ViewCatalog)) {
  throw new IllegalStateException("CREATE OR REPLACE VIEW unsupported on catalog " + catalogName);
}

Type guard

boolean supportsViewReplace(Catalog catalog) {
  return catalog instanceof org.apache.iceberg.catalog.ViewCatalog;
}

Try / catch

try {
  spark.sql("CREATE OR REPLACE VIEW " + ident + " AS " + sqlText);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("Replacing a view is not supported")) {
    // route to a view-capable catalog or use table overwrite
  }
}

Prevention

When it happens

Trigger: Executing CREATE OR REPLACE VIEW (routed to replaceView at SparkCatalog.java:650) against a table-only Iceberg catalog such as HadoopCatalog (spark.sql.catalog.<name>=org.apache.iceberg.hadoop.HadoopCatalog) or a custom Catalog without ViewCatalog support.

Common situations: Migration of view-based pipelines from Hive/JDBC catalogs to environments configured with HadoopCatalog; notebooks that hardcode a catalog URI but change the catalog class; Spark 3.4+ view DDL run on older catalog configs.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:689

        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)
                .createOrReplace();
        return new SparkView(catalogName, view);
      } catch (org.apache.iceberg.exceptions.NoSuchNamespaceException e) {
        throw new NoSuchNamespaceException(currentNamespace);
      } catch (org.apache.iceberg.exceptions.NoSuchViewException e) {
        throw new NoSuchViewException(ident);
      }
    }

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

  @Override
  public View alterView(Identifier ident, ViewChange... changes)
      throws NoSuchViewException, IllegalArgumentException {
    if (null != asViewCatalog) {
      try {
        org.apache.iceberg.view.View view = asViewCatalog.loadView(buildIdentifier(ident));
        UpdateViewProperties updateViewProperties = view.updateProperties();

        for (ViewChange change : changes) {
          if (change instanceof ViewChange.SetProperty) {
            ViewChange.SetProperty property = (ViewChange.SetProperty) change;
            verifyNonReservedPropertyIsSet(property.property());
            updateViewProperties.set(property.property(), property.value());
          } else if (change instanceof ViewChange.RemoveProperty) {
            ViewChange.RemoveProperty remove = (ViewChange.RemoveProperty) change;

View on GitHub (pinned to 86d9c8fc54)