{"record":{"id":"4e7fda19e491446b","repo":"apache/iceberg","slug":"cannot-create-view-s-s-that-references-temporary","errorCode":null,"errorMessage":"Cannot create view %s.%s that references temporary %s: %s","messagePattern":"Cannot create view (.+?)\\.(.+?) that references temporary (.+?): (.+?)","errorType":"exception","errorClass":"AnalysisException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/analysis/RewriteViewCommands.scala","lineNumber":134,"sourceCode":"\n      case UnresolvedIdentifier(CatalogAndIdentifier(catalog, ident), _)\n          if ViewUtil.isViewCatalog(catalog) =>\n        Some(ResolvedIdentifier(catalog, ident))\n\n      case _ =>\n        None\n    }\n  }\n\n  /**\n   * Permanent views are not allowed to reference temp objects\n   */\n  private def verifyTemporaryObjectsDontExist(\n      identifier: ResolvedIdentifier,\n      child: LogicalPlan): Unit = {\n    val tempViews = collectTemporaryViews(child)\n    if (tempViews.nonEmpty) {\n      throw invalidRefToTempObject(\n        identifier,\n        tempViews.map(v => v.quoted).mkString(\"[\", \", \", \"]\"),\n        \"view\")\n    }\n\n    val tempFunctions = collectTemporaryFunctions(child)\n    if (tempFunctions.nonEmpty) {\n      throw invalidRefToTempObject(identifier, tempFunctions.mkString(\"[\", \", \", \"]\"), \"function\")\n    }\n  }\n\n  private def invalidRefToTempObject(\n      ident: ResolvedIdentifier,\n      tempObjectNames: String,\n      tempObjectType: String) = {\n    new AnalysisException(\n      String.format(\n        \"Cannot create view %s.%s that references temporary %s: %s\",","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/analysis/RewriteViewCommands.scala#L116-L152","documentation":"Iceberg's Spark 3.5 RewriteViewCommands rule throws this AnalysisException when a CREATE VIEW targeting a permanent (non-session) view catalog resolves to a plan that references session-scoped temporary objects. Permanent views store their SQL text and must be resolvable independent of the creator's session, so temp views/functions (which die with the session) may not appear in their definition. The check runs in verifyTemporaryObjectsDontExist during analysis of CreateViewCommand-like plans.","triggerScenarios":"Running `CREATE VIEW iceberg_catalog.db.permanent_view AS SELECT ... FROM temp_view` where temp_view was created via `CREATE TEMPORARY VIEW`, or `CREATE VIEW cat.db.v AS SELECT temp_fn(col) FROM t` where temp_fn is a session temporary function. The message names the offending object and whether it was a temporary view or function.","commonSituations":"Developers migrate a session temp view to a persistent Iceberg view by re-running the definition with CREATE VIEW but forgetting the body still reads from a temp view or uses a temp UDF. Also common in notebooks where setup code creates temp views, then a persistent view is defined on top of them; works in dev session, fails on restart.","solutions":["Replace the temporary view reference with a persistent table or view (e.g., CREATE OR REPLACE TABLE / VIEW in a real catalog) before creating the permanent view.","Inline the temp view's query into the new view definition: CREATE VIEW cat.db.v AS SELECT * FROM (<temp view query>).","Replace temporary function usage with a permanent function registered in the catalog, or inline its logic.","If the intent was session-local, create the view in the session catalog instead: CREATE TEMPORARY VIEW tmp AS ... or omit the Iceberg catalog prefix.","If defining multiple persistent views from temp views, create them bottom-up: first persist the base temp view, then create dependent views."],"exampleFix":"// before (fails)\nCREATE TEMPORARY VIEW tmp_filtered AS SELECT * FROM events WHERE day = '2026-01-01';\nCREATE VIEW iceberg.db.daily AS SELECT * FROM tmp_filtered;\n\n// after (works)\nCREATE TABLE iceberg.db.daily_base AS SELECT * FROM events WHERE day = '2026-01-01';\nCREATE VIEW iceberg.db.daily AS SELECT * FROM iceberg.db.daily_base;","handlingStrategy":"validation","validationCode":"// Spark 3.5 (Scala): check plan for temp views before CREATE VIEW on a view catalog\nval analyzed = spark.sessionState.executePlan(df.queryExecution.logical).analyzed\nval usesTemp = analyzed.flatMap {\n  case r: org.apache.spark.sql.catalyst.analysis.UnresolvedRelation\n    if spark.sessionState.catalog.isTempView(r.multipartIdentifier) => true\n  case _ => false\n}.nonEmpty\nif (usesTemp) throw new IllegalStateException(\"view body references temp views; persist them first\")","typeGuard":"def referencesTempView(sql: String, spark: SparkSession): Boolean =\n  spark.sessionState.catalog.listTempViews().exists(v => sql.contains(v.name))","tryCatchPattern":null,"preventionTips":["Never reference CREATE TEMPORARY VIEW objects inside CREATE VIEW statements targeting an Iceberg/view catalog.","Persist intermediate results as tables or permanent views before building dependent views.","Register shared UDFs as permanent catalog functions, not temporary ones.","In notebooks, keep a convention: temp views are staging only; final views must inline or reference catalog objects.","Test view creation in a fresh session — anything that fails there will hit this error."],"tags":["spark","view","temporary-object","analysis-exception","iceberg"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}