{"record":{"id":"bb7dc46f5d97bd43","repo":"apache/iceberg","slug":"named-and-positional-arguments-cannot-be-mixed","errorCode":null,"errorMessage":"Named and positional arguments cannot be mixed","messagePattern":"Named and positional arguments cannot be mixed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveProcedures.scala","lineNumber":123,"sourceCode":"      case p if !p.required && !nameToArgMap.contains(p.name) =>\n        val position = nameToPositionMap(p.name)\n        argExprs(position) = Literal.create(null, p.dataType)\n      case _ =>\n    }\n\n    argExprs\n  }\n\n  private def buildNameToArgMap(\n      params: Seq[ProcedureParameter],\n      args: Seq[CallArgument],\n      nameToPositionMap: Map[String, Int]): Map[String, CallArgument] = {\n\n    val containsNamedArg = args.exists(_.isInstanceOf[NamedArgument])\n    val containsPositionalArg = args.exists(_.isInstanceOf[PositionalArgument])\n\n    if (containsNamedArg && containsPositionalArg) {\n      throw new AnalysisException(\"Named and positional arguments cannot be mixed\")\n    }\n\n    if (containsNamedArg) {\n      buildNameToArgMapUsingNames(args, nameToPositionMap)\n    } else {\n      buildNameToArgMapUsingPositions(args, params)\n    }\n  }\n\n  private def buildNameToArgMapUsingNames(\n      args: Seq[CallArgument],\n      nameToPositionMap: Map[String, Int]): Map[String, CallArgument] = {\n\n    val namedArgs = args.asInstanceOf[Seq[NamedArgument]]\n\n    val validationErrors = namedArgs.groupBy(_.name).collect {\n      case (name, matchingArgs) if matchingArgs.size > 1 => s\"Duplicate procedure argument: $name\"\n      case (name, _) if !nameToPositionMap.contains(name) => s\"Unknown argument: $name\"","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveProcedures.scala#L105-L141","documentation":"Thrown by ResolveProcedures when a single CALL mixes positional and named arguments. Iceberg requires invocation to use entirely positional or entirely named arguments; mixing makes the mapping ambiguous, so analysis fails.","triggerScenarios":"CALL catalog.system.proc('db.t', where => 'id > 1') — first arg positional, second named.","commonSituations":"Extending an existing positional call with a named argument for one optional parameter; copying example DDL that used the other invocation style.","solutions":["Convert all arguments to named form: param => value for every argument","Convert all arguments to positional form, ordering them exactly as the procedure declares them"],"exampleFix":"// before\nCALL catalog.system.rewrite_data_files('db.t', where => 'id > 1')\n// after\nCALL catalog.system.rewrite_data_files(table => 'db.t', where => 'id > 1')","handlingStrategy":"validation","validationCode":"val styles = callArgs.map(a => if (a.isInstanceOf[NamedArgument]) \"named\" else \"positional\").distinct\nrequire(styles.size <= 1, \"CALL must use all named or all positional arguments\")","typeGuard":null,"tryCatchPattern":"try { spark.sql(callSql) } catch { case e: AnalysisException if e.getMessage == \"Named and positional arguments cannot be mixed\" => // normalize argument style }","preventionTips":["Standardize on fully named invocation for procedures with optional parameters","Never append a named argument to an existing positional call — convert all arguments at once"],"tags":["spark","sql","call-procedure","named-arguments"],"backgroundTag":"mutually-exclusive-options","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"}