{"record":{"id":"af94822ccfddfb27","repo":"apache/iceberg","slug":"cannot-move-view-between-catalogs-from-oldcatal","errorCode":null,"errorMessage":"Cannot move view between catalogs: from=${oldCatalog.name} and to=${newIdent.catalog().name()}","messagePattern":"Cannot move view between catalogs: from=(.+?) and to=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/ExtendedDataSourceV2Strategy.scala","lineNumber":132,"sourceCode":"    case SetIdentifierFields(IcebergCatalogAndIdentifier(catalog, ident), fields) =>\n      SetIdentifierFieldsExec(catalog, ident, fields) :: Nil\n\n    case DropIdentifierFields(IcebergCatalogAndIdentifier(catalog, ident), fields) =>\n      DropIdentifierFieldsExec(catalog, ident, fields) :: Nil\n\n    case SetWriteDistributionAndOrdering(\n          IcebergCatalogAndIdentifier(catalog, ident),\n          distributionMode,\n          ordering) =>\n      SetWriteDistributionAndOrderingExec(catalog, ident, distributionMode, ordering) :: Nil\n\n    case OrderAwareCoalesce(numPartitions, coalescer, child) =>\n      OrderAwareCoalesceExec(numPartitions, coalescer, planLater(child)) :: Nil\n\n    case RenameTable(ResolvedV2View(oldCatalog: ViewCatalog, oldIdent), newName, isView @ true) =>\n      val newIdent = Spark3Util.catalogAndIdentifier(spark, newName.toList.asJava)\n      if (oldCatalog.name != newIdent.catalog().name()) {\n        throw new AnalysisException(\n          s\"Cannot move view between catalogs: from=${oldCatalog.name} and to=${newIdent.catalog().name()}\")\n      }\n      RenameV2ViewExec(oldCatalog, oldIdent, newIdent.identifier()) :: Nil\n\n    case DropIcebergView(ResolvedIdentifier(viewCatalog: ViewCatalog, ident), ifExists) =>\n      DropV2ViewExec(viewCatalog, ident, ifExists) :: Nil\n\n    case CreateIcebergView(\n          ResolvedIdentifier(viewCatalog: ViewCatalog, ident),\n          queryText,\n          query,\n          columnAliases,\n          columnComments,\n          queryColumnNames,\n          comment,\n          properties,\n          allowExisting,\n          replace,","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/ExtendedDataSourceV2Strategy.scala#L114-L150","documentation":"ExtendedDataSourceV2Strategy throws this AnalysisException when ALTER VIEW ... RENAME TO resolves to a different catalog than the one holding the original view. Iceberg's ViewCatalog supports renaming views only within the same catalog; cross-catalog moves are not implemented. The strategy compares oldCatalog.name with the catalog parsed from the new name and fails fast before building the RenameV2ViewExec.","triggerScenarios":"ALTER VIEW cat1.db.v RENAME TO cat2.db.v2 where Spark3Util.catalogAndIdentifier resolves the new name to catalog cat2, different from the view's source catalog cat1.","commonSituations":"Users assuming RENAME can move views across catalogs like a copy+drop; default-catalog resolution silently picking the session catalog instead of the source catalog; migration scripts rewriting view names with a different catalog prefix.","solutions":["Rename within the same catalog: ALTER VIEW cat1.db.v RENAME TO cat1.db.v2.","To move a catalog, create the view in the target catalog (CREATE VIEW ... AS SELECT * FROM old) and drop the original.","Remove the unintended catalog prefix so the new name resolves to the source catalog.","Check Spark3Util.catalogAndIdentifier output by logging/spark.sql which catalog the new name binds to."],"exampleFix":"-- before\nALTER VIEW cat1.db.metrics_summary RENAME TO cat2.db.metrics_summary;\n-- after\nALTER VIEW cat1.db.metrics_summary RENAME TO cat1.db.metrics_summary_v2;","handlingStrategy":"validation","validationCode":"val target = Spark3Util.catalogAndIdentifier(spark, newName)\nif (target.catalog().name() != sourceCatalogName) throw new AnalysisException(\"rename must stay within the source catalog\")","typeGuard":null,"tryCatchPattern":"try { spark.sql(s\"ALTER VIEW $oldName RENAME TO $newName\") } catch { case e: org.apache.spark.sql.AnalysisException if e.getMessage.contains(\"Cannot move view between catalogs\") => log.error(\"cross-catalog view rename unsupported; recreate view instead\") }","preventionTips":["Never include a different catalog prefix in the RENAME TO name","To relocate a view, CREATE VIEW in the target catalog then DROP the original","Remember the session default catalog is used when the new name has no catalog prefix"],"tags":["spark","views","rename","catalogs"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}