prestodb/presto · error · SemanticException
TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT
TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT
Error message
Duplicate argument name: %s
What it means
When analyzing a table function invocation, StatementAnalyzer collects each named argument's canonical name into a Set. If the same argument name appears twice, the set-add fails and this SemanticException (TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT) is thrown. Table function arguments must be passed by unique names because each name is matched to exactly one ArgumentSpecification.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java:1977
}
}
private ArgumentsAnalysis mapTableFunctionsArgsByName(List<ArgumentSpecification> argumentSpecifications, List<TableFunctionArgument> arguments, Node errorLocation, Optional<Scope> scope)
{
ImmutableMap.Builder<String, Argument> passedArguments = ImmutableMap.builder();
ImmutableList.Builder<TableArgumentAnalysis> tableArgumentAnalyses = ImmutableList.builder();
Map<String, ArgumentSpecification> argumentSpecificationsByName = new HashMap<>();
for (ArgumentSpecification argumentSpecification : argumentSpecifications) {
if (argumentSpecificationsByName.put(argumentSpecification.getName(), argumentSpecification) != null) {
// this should never happen, because the argument names are validated at function registration time
throw new IllegalStateException("Duplicate argument specification for name: " + argumentSpecification.getName());
}
}
Set<String> uniqueArgumentNames = new HashSet<>();
for (TableFunctionArgument argument : arguments) {
String argumentName = argument.getName().orElseThrow(() -> new IllegalStateException("Missing table function argument name")).getCanonicalValue();
if (!uniqueArgumentNames.add(argumentName)) {
throw new SemanticException(TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT, argument, "Duplicate argument name: %s", argumentName);
}
ArgumentSpecification argumentSpecification = argumentSpecificationsByName.remove(argumentName);
if (argumentSpecification == null) {
throw new SemanticException(TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT, argument, "Unexpected argument name: %s", argumentName);
}
ArgumentAnalysis argumentAnalysis = analyzeArgument(argumentSpecification, argument, scope);
passedArguments.put(argumentSpecification.getName(), argumentAnalysis.getArgument());
argumentAnalysis.getTableArgumentAnalysis().ifPresent(tableArgumentAnalyses::add);
}
// apply defaults for not specified arguments
for (Map.Entry<String, ArgumentSpecification> entry : argumentSpecificationsByName.entrySet()) {
ArgumentSpecification argumentSpecification = entry.getValue();
passedArguments.put(argumentSpecification.getName(), analyzeDefault(argumentSpecification, errorLocation));
}
return new ArgumentsAnalysis(passedArguments.buildOrThrow(), tableArgumentAnalyses.build());
}
private ArgumentsAnalysis mapTableFunctionArgsByPosition(List<ArgumentSpecification> argumentSpecifications, List<TableFunctionArgument> arguments, Node errorLocation, Optional<Scope> scope)View on GitHub (pinned to 55bb57d202)
Solutions
- Remove the duplicate named argument from the TABLE() invocation, keeping the intended value.
- Rename the second argument if it was a typo and actually corresponds to a different parameter of the function.
- Check the function's declared argument specifications (SHOW FUNCTIONS / docs) to confirm the correct argument names.
Example fix
// before SELECT * FROM TABLE(my_fn(key => 'a', key => 'b')); // after SELECT * FROM TABLE(my_fn(key => 'a', other => 'b'));
Defensive patterns
Strategy: validation
Validate before calling
// Java: dedupe named table function args before building the invocation
Set<String> seen = new HashSet<>();
for (TableFunctionArgument a : arguments) {
String name = a.getName().orElseThrow().getCanonicalValue();
if (!seen.add(name)) {
throw new IllegalArgumentException("Duplicate table function argument: " + name);
}
} Type guard
boolean isUniqueArgs(List<TableFunctionArgument> args) {
return args.stream()
.map(a -> a.getName().map(Node::getCanonicalValue).orElse(null))
.collect(toSet()).size() == args.size();
} Try / catch
try {
analyzeTableFunctionCall(node, ...);
} catch (SemanticException e) {
if (e.getCode() == TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT) {
// surface "duplicate argument name" to caller with argument name from e.getErrorMessage()
}
} Prevention
- Keep argument lists in one place; never concatenate argument fragments from multiple sources.
- Remember argument names are compared case-insensitively — don't rely on casing to differentiate.
- Validate generated SQL with a parser before submission.
When it happens
Trigger: Calling a table function in a FROM clause with the same named argument supplied twice, e.g. `SELECT * FROM TABLE(my_fn(arg => 1, arg => 2))`. Canonical name comparison is case-insensitive via getCanonicalValue(), so `Arg => 1, ARG => 2` also triggers it.
Common situations: Copy-paste of an argument list where one argument wasn't updated; combining generated SQL fragments that both supply the same argument; misunderstanding case-insensitivity of argument names; typo where the second argument was meant to have a different name.
Related errors
- TABLE_FUNCTION_MISSING_ARGUMENT
- INVALID_FUNCTION_ARGUMENT
- MUST_BE_AGGREGATE_OR_GROUP_BY
- NESTED_AGGREGATION
- NESTED_WINDOW
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/83f4696ad7f1bb8a.
Report an issue: GitHub.