{"record":{"id":"83f4696ad7f1bb8a","repo":"prestodb/presto","slug":"table-function-invalid-function-argument","errorCode":"TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT","errorMessage":"Duplicate argument name: %s","messagePattern":"Duplicate argument name: (.+?)","errorType":"error_code","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java","lineNumber":1977,"sourceCode":"            }\n        }\n\n        private ArgumentsAnalysis mapTableFunctionsArgsByName(List<ArgumentSpecification> argumentSpecifications, List<TableFunctionArgument> arguments, Node errorLocation, Optional<Scope> scope)\n        {\n            ImmutableMap.Builder<String, Argument> passedArguments = ImmutableMap.builder();\n            ImmutableList.Builder<TableArgumentAnalysis> tableArgumentAnalyses = ImmutableList.builder();\n            Map<String, ArgumentSpecification> argumentSpecificationsByName = new HashMap<>();\n            for (ArgumentSpecification argumentSpecification : argumentSpecifications) {\n                if (argumentSpecificationsByName.put(argumentSpecification.getName(), argumentSpecification) != null) {\n                    // this should never happen, because the argument names are validated at function registration time\n                    throw new IllegalStateException(\"Duplicate argument specification for name: \" + argumentSpecification.getName());\n                }\n            }\n            Set<String> uniqueArgumentNames = new HashSet<>();\n            for (TableFunctionArgument argument : arguments) {\n                String argumentName = argument.getName().orElseThrow(() -> new IllegalStateException(\"Missing table function argument name\")).getCanonicalValue();\n                if (!uniqueArgumentNames.add(argumentName)) {\n                    throw new SemanticException(TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT, argument, \"Duplicate argument name: %s\", argumentName);\n                }\n                ArgumentSpecification argumentSpecification = argumentSpecificationsByName.remove(argumentName);\n                if (argumentSpecification == null) {\n                    throw new SemanticException(TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT, argument, \"Unexpected argument name: %s\", argumentName);\n                }\n                ArgumentAnalysis argumentAnalysis = analyzeArgument(argumentSpecification, argument, scope);\n                passedArguments.put(argumentSpecification.getName(), argumentAnalysis.getArgument());\n                argumentAnalysis.getTableArgumentAnalysis().ifPresent(tableArgumentAnalyses::add);\n            }\n            // apply defaults for not specified arguments\n            for (Map.Entry<String, ArgumentSpecification> entry : argumentSpecificationsByName.entrySet()) {\n                ArgumentSpecification argumentSpecification = entry.getValue();\n                passedArguments.put(argumentSpecification.getName(), analyzeDefault(argumentSpecification, errorLocation));\n            }\n            return new ArgumentsAnalysis(passedArguments.buildOrThrow(), tableArgumentAnalyses.build());\n        }\n\n        private ArgumentsAnalysis mapTableFunctionArgsByPosition(List<ArgumentSpecification> argumentSpecifications, List<TableFunctionArgument> arguments, Node errorLocation, Optional<Scope> scope)","sourceCodeStart":1959,"sourceCodeEnd":1995,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java#L1959-L1995","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nSELECT * FROM TABLE(my_fn(key => 'a', key => 'b'));\n// after\nSELECT * FROM TABLE(my_fn(key => 'a', other => 'b'));","handlingStrategy":"validation","validationCode":"// Java: dedupe named table function args before building the invocation\nSet<String> seen = new HashSet<>();\nfor (TableFunctionArgument a : arguments) {\n    String name = a.getName().orElseThrow().getCanonicalValue();\n    if (!seen.add(name)) {\n        throw new IllegalArgumentException(\"Duplicate table function argument: \" + name);\n    }\n}","typeGuard":"boolean isUniqueArgs(List<TableFunctionArgument> args) {\n    return args.stream()\n        .map(a -> a.getName().map(Node::getCanonicalValue).orElse(null))\n        .collect(toSet()).size() == args.size();\n}","tryCatchPattern":"try {\n    analyzeTableFunctionCall(node, ...);\n} catch (SemanticException e) {\n    if (e.getCode() == TABLE_FUNCTION_INVALID_FUNCTION_ARGUMENT) {\n        // surface \"duplicate argument name\" to caller with argument name from e.getErrorMessage()\n    }\n}","preventionTips":["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."],"tags":["sql","table-function","semantic-analysis","duplicate-argument"],"backgroundTag":"duplicate-named-argument","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}