apache/iceberg · error

cannotCreateViewTooManyColumnsError(viewNameParts, columns…

Error message

cannotCreateViewTooManyColumnsError(viewNameParts, columns, query)

What it means

Companion case to the not-enough-columns check: when the explicit column list in CREATE VIEW is longer than the query output, CheckViews throws cannotCreateViewTooManyColumnsError. Spark requires a 1:1 correspondence between declared view columns and query output columns.

Solutions

  1. Remove extra names from the column list so counts match the query output
  2. Extend the SELECT to produce one column per declared name (e.g. add expression or constant)
  3. Drop the explicit column list and rely on query output names/aliases

Example fix

-- before
CREATE VIEW v (a, b, c) AS SELECT x, y FROM t;
-- after
CREATE VIEW v (a, b) AS SELECT x, y FROM t;
Defensive patterns

Strategy: validation

Validate before calling

val querySchema = spark.sql(query).schema
require(namedColumns.length == querySchema.length,
  s"declared ${namedColumns.length} columns but query returns ${querySchema.length}")

Prevention

When it happens

Trigger: `CREATE VIEW v (a, b, c) AS SELECT x, y FROM t` — declared column list has more names than the SELECT produces; caught during analysis in CheckViews.checkColumnNames for CreateViewStatement with ResolvedIdentifier.

Common situations: Copy-pasted CREATE VIEW with a stale column list; generated SQL where the query was narrowed but the column list was not; adding columns to the list in anticipation of query changes that never landed.

Related errors


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

Appendix: source

Thrown at spark/v4.2/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/analysis/CheckViews.scala:80

          "ALTER VIEW <viewName> AS is not supported. Use CREATE OR REPLACE VIEW instead")

      case _ => // OK
    }
  }

  private def verifyColumnCount(
      ident: ResolvedIdentifier,
      columns: Seq[String],
      query: LogicalPlan): Unit = {
    if (columns.nonEmpty) {
      val viewNameParts = ident.catalog.name() +: ident.identifier.asMultipartIdentifier
      if (columns.length > query.output.length) {
        throw QueryCompilationErrors.cannotCreateViewNotEnoughColumnsError(
          viewNameParts,
          columns,
          query)
      } else if (columns.length < query.output.length) {
        throw QueryCompilationErrors.cannotCreateViewTooManyColumnsError(
          viewNameParts,
          columns,
          query)
      }
    }
  }

  // Spark's ViewHelper.checkCyclicViewReference only matches a SubqueryExpression at the root of
  // each expression. Keep a custom traversal so cycles in predicates and other nested expressions
  // are detected.
  private def checkCyclicViewReference(
      viewIdent: Seq[String],
      plan: LogicalPlan,
      cyclePath: Seq[Seq[String]]): Unit = {
    plan match {
      case v1View: View =>
        val currentViewIdent: Seq[String] = v1View.desc.fullIdent
        checkIfRecursiveView(viewIdent, currentViewIdent, cyclePath, v1View.children)

View on GitHub (pinned to 86d9c8fc54)