apache/iceberg · error · AnalysisException
Duplicate parameter names
Error message
Duplicate parameter names: ${duplicateParamNames.mkString("[", ",", "]")} What it means
Thrown by ResolveProcedures when a procedure's parameter list contains two or more parameters sharing the same name. Duplicate names make named-argument invocation ambiguous, so procedure resolution rejects it at analysis time.
Solutions
- Rename one of the duplicated procedure parameters so every parameter name is unique
- If parameters are generated from schema fields, deduplicate or prefix field names before building ProcedureParameter instances
Example fix
// before
ProcedureParameter.required("table"), ProcedureParameter.optional("table", StringType)
// after
ProcedureParameter.required("table"), ProcedureParameter.optional("where", StringType) Defensive patterns
Strategy: validation
Validate before calling
val names = params.map(_.name)
require(names.distinct.size == names.size, s"duplicate param names: ${names.diff(names.distinct).mkString(",")}") Try / catch
try { spark.sql(callSql) } catch { case e: AnalysisException if e.getMessage.startsWith("Duplicate parameter names") => // fix procedure definition } Prevention
- Generate procedure parameters from deduplicated schema field names
- Add a unit test asserting parameter name uniqueness for custom procedures
When it happens
Trigger: Registering/defining a procedure whose ProcedureParameter list has repeated names, then resolving a CALL against it.
Common situations: Programmatic procedure definitions where parameters are generated from a schema and two columns share a (case-insensitively equal) name; hand-rolled procedure catalogs with copy-pasted parameter declarations.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Optional parameters must be after required ones but…
- CREATE_VIEW_COLUMN_ARITY_MISMATCH.TOO_MANY_DATA_COLUMNS
- ALTER TABLE contains multiple distribution clauses
- ALTER TABLE contains multiple distribution clauses
- ALTER TABLE contains multiple ordering clauses
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/f396c0086e431301.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveProcedures.scala:63
case CallStatement(CatalogAndIdentifier(catalog, ident), args) =>
val procedure = catalog.asProcedureCatalog.loadProcedure(ident)
val params = procedure.parameters
val normalizedParams = normalizeParams(params)
validateParams(normalizedParams)
val normalizedArgs = normalizeArgs(args)
Call(procedure, args = buildArgExprs(normalizedParams, normalizedArgs).toSeq)
}
private def validateParams(params: Seq[ProcedureParameter]): Unit = {
// should not be any duplicate param names
val duplicateParamNames = params.groupBy(_.name).collect {
case (name, matchingParams) if matchingParams.length > 1 => name
}
if (duplicateParamNames.nonEmpty) {
throw new AnalysisException(
s"Duplicate parameter names: ${duplicateParamNames.mkString("[", ",", "]")}")
}
// optional params should be at the end
params.sliding(2).foreach {
case Seq(previousParam, currentParam) if !previousParam.required && currentParam.required =>
throw new AnalysisException(
s"Optional parameters must be after required ones but $currentParam is after $previousParam")
case _ =>
}
}
private def buildArgExprs(
params: Seq[ProcedureParameter],
args: Seq[CallArgument]): Seq[Expression] = {
// build a map of declared parameter names to their positions
val nameToPositionMap = params.map(_.name).zipWithIndex.toMapView on GitHub (pinned to 86d9c8fc54)