{"record":{"id":"8265ec811bbeb910","repo":"apache/iceberg","slug":"invalid-transform-argument-8265ec","errorCode":null,"errorMessage":"Invalid transform argument","messagePattern":"Invalid transform argument","errorType":"exception","errorClass":"IcebergParseException","httpStatus":null,"severity":"error","filePath":"spark/v4.2/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/IcebergSqlExtensionsAstBuilder.scala","lineNumber":315,"sourceCode":"  override def visitApplyTransform(ctx: ApplyTransformContext): Transform = withOrigin(ctx) {\n    val args = toSeq(ctx.arguments).map(typedVisit[expressions.Expression])\n    ApplyTransform(ctx.transformName.getText, args)\n  }\n\n  /**\n   * Create a transform argument from a column reference or a constant.\n   */\n  override def visitTransformArgument(ctx: TransformArgumentContext): expressions.Expression =\n    withOrigin(ctx) {\n      val reference = Option(ctx.multipartIdentifier())\n        .map(typedVisit[Seq[String]])\n        .map(FieldReference(_))\n      val literal = Option(ctx.constant)\n        .map(visitConstant)\n        .map(lit => LiteralValue(lit.value, lit.dataType))\n      reference\n        .orElse(literal)\n        .getOrElse(throw new IcebergParseException(s\"Invalid transform argument\", ctx))\n    }\n\n  /**\n   * Return a multi-part identifier as Seq[String].\n   */\n  override def visitMultipartIdentifier(ctx: MultipartIdentifierContext): Seq[String] =\n    withOrigin(ctx) {\n      toSeq(ctx.parts).map(_.getText)\n    }\n\n  override def visitSingleOrder(ctx: SingleOrderContext): Seq[(Term, SortDirection, NullOrder)] =\n    withOrigin(ctx) {\n      toSeq(ctx.order.fields).map(typedVisit[(Term, SortDirection, NullOrder)])\n    }\n\n  override def visitSingleStatement(ctx: SingleStatementContext): LogicalPlan = withOrigin(ctx) {\n    visit(ctx.statement).asInstanceOf[LogicalPlan]\n  }","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/IcebergSqlExtensionsAstBuilder.scala#L297-L333","documentation":"When building a transform from the grammar (e.g. bucket[N](col), truncate[L](col), year/month/day/hour(col) or a literal argument), the builder expects the argument to be either a column reference or a constant literal; if ctx has neither (or both parse to nothing), it throws IcebergParseException \"Invalid transform argument\".","triggerScenarios":"Writing a transform with a missing or malformed argument, e.g. `bucket(4)()`, `truncate[]`, an expression that is neither a column nor a literal such as `bucket(4)(a + b)`, or an empty argument in a procedure/DDL transform position.","commonSituations":"Typos in partition-evolution DDL like `ALTER TABLE t ADD PARTITION FIELD bucket(16)()`; programmatic SQL generation emitting empty transform arguments; using complex expressions where only identifiers or literals are accepted.","solutions":["Supply a column reference as the argument: `bucket(16)(col)` / `truncate(10)(col)`.","Or supply a constant literal where the transform accepts one, e.g. identity-like positional references in CALL procedures.","Remove complex expressions; precompute the value or add a column to the table instead.","Check the statement against the Iceberg transform grammar (bucket[N], truncate[L], year, month, day, hour, identity)."],"exampleFix":"-- before\nALTER TABLE t ADD PARTITION FIELD days(a + b) AS d\n-- after\nALTER TABLE t ADD PARTITION FIELD days(event_ts) AS d","handlingStrategy":"validation","validationCode":"// Validate transform argument is a bare column or literal before submitting\nval transform = s\"$name($arg)\"\nval valid = arg.matches(\"[A-Za-z_][A-Za-z0-9_.]*\") || arg.matches(\"-?\\\\d+\")\nrequire(valid, s\"Transform argument must be a column reference or literal: $transform\")","typeGuard":null,"tryCatchPattern":"try { spark.sql(stmt) } catch {\n  case e: IcebergParseException if e.getMessage.contains(\"Invalid transform argument\") =>\n    throw new IllegalArgumentException(s\"Fix transform to e.g. $name(col)\", e)\n}","preventionTips":["Always pass a plain column name or literal to bucket/truncate/year/month/day/hour transforms","Precompute complex expressions into a table column before partitioning by them","Check transform syntax against Iceberg docs when generating partition DDL programmatically"],"tags":["spark","sql-parser","partition-transform","invalid-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}