lsherwin10 opened a new issue, #18662: URL: https://github.com/apache/iceberg/issues/18662
### Apache Iceberg version 1.10.1 ### Query engine Spark ### Please describe the bug 🐞 In `RESTSessionCatalog.Builder.replaceTransaction()` ([lines 828–832](https://github.com/apache/iceberg/blob/apache-iceberg-1.10.1/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java#L828-L832)), the client unconditionally checks `if (viewExists(context, ident))` before staging a replacement table: ```java @Override public Transaction replaceTransaction() { Endpoint.check(endpoints, Endpoint.V1_UPDATE_TABLE); if (viewExists(context, ident)) { throw new AlreadyExistsException("View with same name already exists: %s", ident); } ... ``` When connecting to a REST catalog with table-only permissions where view endpoints are supported, `/views/{view}` returns `HTTP 403 Forbidden`. Because `viewExists()` does not catch `ForbiddenException`, `CREATE OR REPLACE TABLE` fails even though the caller has full table rights: ```text 26/10/26 22:46:52 ERROR SparkSQLDriver: Failed in [create or replace table test_table (id INT, data STRING)] org.apache.iceberg.exceptions.ForbiddenException: Forbidden: Forbidden at org.apache.iceberg.rest.ErrorHandlers$DefaultErrorHandler.accept(ErrorHandlers.java:238) at org.apache.iceberg.rest.ErrorHandlers$ViewErrorHandler.accept(ErrorHandlers.java:168) at org.apache.iceberg.rest.ErrorHandlers$ViewErrorHandler.accept(ErrorHandlers.java:152) at org.apache.iceberg.rest.HTTPClient.throwFailure(HTTPClient.java:240) at org.apache.iceberg.rest.HTTPClient.execute(HTTPClient.java:336) at org.apache.iceberg.rest.HTTPClient.execute(HTTPClient.java:297) at org.apache.iceberg.rest.BaseHTTPClient.head(BaseHTTPClient.java:45) at org.apache.iceberg.rest.RESTSessionCatalog.viewExists(RESTSessionCatalog.java:1112) at org.apache.iceberg.rest.RESTSessionCatalog$Builder.replaceTransaction(RESTSessionCatalog.java:830) at org.apache.iceberg.rest.RESTSessionCatalog$Builder.createOrReplaceTransaction(RESTSessionCatalog.java:899) at org.apache.iceberg.CachingCatalog$CachingTableBuilder.createOrReplaceTransaction(CachingCatalog.java:302) at org.apache.iceberg.spark.SparkCatalog.stageCreateOrReplace(SparkCatalog.java:303) at org.apache.spark.sql.connector.catalog.StagingTableCatalog.stageCreateOrReplace(StagingTableCatalog.java:188) at org.apache.spark.sql.execution.datasources.v2.AtomicReplaceTableExec.run(ReplaceTableExec.scala:75) at org.apache.spark.sql.execution.datasources.v2.V2CommandExec.result$lzycompute(V2CommandExec.scala:43) at org.apache.spark.sql.execution.datasources.v2.V2CommandExec.result(V2CommandExec.scala:43) at org.apache.spark.sql.execution.datasources.v2.V2CommandExec.executeCollect(V2CommandExec.scala:49) at org.apache.spark.sql.execution.QueryExecution$$anonfun$eagerlyExecuteCommands$1.$anonfun$applyOrElse$1(QueryExecution.scala:107) at org.apache.spark.sql.execution.SQLExecution$.$anonfun$withNewExecutionId$6(SQLExecution.scala:125) at org.apache.spark.sql.execution.SQLExecution$.withSQLConfPropagated(SQLExecution.scala:201) at org.apache.spark.sql.execution.SQLExecution$.$anonfun$withNewExecutionId$1(SQLExecution.scala:108) at org.apache.spark.sql.SparkSession.withActive(SparkSession.scala:900) ``` Additionally, configuring `spark.sql.catalog.<name>.view-endpoints-supported = false` has no effect because `RESTSessionCatalog.initialize()` only checks this property when `config.endpoints().isEmpty()`. If the server advertises view endpoints in `/v1/config`, the client setting is ignored. #### What to expect - `CREATE OR REPLACE TABLE` should succeed when the user has table permissions, without requiring view permissions (matching `createTransaction()`, which does not call `viewExists()`). - Setting `view-endpoints-supported = false` should allow clients to disable view endpoints even if the server advertises them. #### How to reproduce 1. Configure an Iceberg REST catalog where view endpoints are exposed and perform auth checks, the credentials grant access to tables, but deny access to views. 2. Run: ```sql CREATE TABLE cat.db.orders (id INT) USING iceberg; CREATE OR REPLACE TABLE cat.db.orders (id INT, status STRING) USING iceberg; ``` 3. `CREATE TABLE` succeeds, but `CREATE OR REPLACE TABLE` fails with `ForbiddenException: 403`. ### Willingness to contribute - [ ] I can contribute a fix for this bug independently - [ ] I would be willing to contribute a fix for this bug with guidance from the Iceberg community - [ ] I cannot contribute a fix for this bug at this time -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
