{"record":{"id":"741ba9db05a2517d","repo":"apache/iceberg","slug":"invalid-transform-argument","errorCode":null,"errorMessage":"Invalid transform argument","messagePattern":"Invalid transform argument","errorType":"exception","errorClass":"IcebergParseException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/IcebergSqlExtensionsAstBuilder.scala","lineNumber":328,"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  /**\n   * Create a positional argument in a stored procedure call.\n   */","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/IcebergSqlExtensionsAstBuilder.scala#L310-L346","documentation":"In transforms like bucket(N, arg) or truncate(W, arg), the transform argument must be either a column reference or a constant literal. If the argument context provides neither (missing/unsupported argument form), an IcebergParseException is thrown.","triggerScenarios":"Parsing a partition transform with an empty or non-reference/non-constant argument, e.g. 'bucket(2, )' or grammar contexts where ctx.field and ctx.constant are both absent.","commonSituations":"Hand-written DDL with a missing transform argument; macro/template-generated SQL leaving a placeholder empty.","solutions":["Supply a column name: e.g. PARTITIONED BY (bucket(16, id))","Supply a constant literal where allowed, e.g. truncate(10, 'abc')","Verify the transform's grammar — transforms require exactly one argument between the parentheses"],"exampleFix":"// before\nALTER TABLE t ADD PARTITION FIELD bucket(16, );\n// after\nALTER TABLE t ADD PARTITION FIELD bucket(16, id);","handlingStrategy":"validation","validationCode":"val transform = \"bucket\\\\(([^)]*)\\\\)\".r.findAllIn(ddl).toList\ntransform.foreach(t => require(t.split(\",\").length == 2 && t.trim.endsWith(\")\") && !t.endsWith(\"(, )\"), s\"Transform needs a column or literal argument: $t\")","typeGuard":null,"tryCatchPattern":"try { spark.sql(ddl) } catch { case e: IcebergParseException if e.getMessage.contains(\"Invalid transform argument\") => log.error(\"empty transform argument\"); throw e }","preventionTips":["Always pass a column reference or literal as the second transform argument","Never template transforms with empty placeholders","Check Iceberg transform grammar (bucket/truncate/year/month/day/hour) before writing DDL"],"tags":["spark","parser","transform","partitioning"],"backgroundTag":"missing-required-argument","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"}