{"record":{"id":"dcc9645208448428","repo":"prestodb/presto","slug":"ambiguous-function-call-dcc964","errorCode":"AMBIGUOUS_FUNCTION_CALL","errorMessage":"Could not choose a best candidate operator. Explicit type casts must be added.\nCandidates are:\n","messagePattern":"Could not choose a best candidate operator\\. Explicit type casts must be added\\.\nCandidates are:\n","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionSignatureMatcher.java","lineNumber":130,"sourceCode":"    {\n        List<ApplicableFunction> applicableFunctions = identifyApplicableFunctions(candidates, actualParameters, false);\n        if (applicableFunctions.isEmpty()) {\n            return Optional.empty();\n        }\n\n        if (applicableFunctions.size() == 1) {\n            return Optional.of(applicableFunctions.stream().collect(onlyElement()).getBoundSignature());\n        }\n\n        List<Signature> deduplicatedSignatures = applicableFunctions.stream()\n                .map(applicableFunction -> applicableFunction.boundSignature)\n                .distinct()\n                .collect(toImmutableList());\n        if (deduplicatedSignatures.size() == 1) {\n            return Optional.of(deduplicatedSignatures.stream().collect(onlyElement()));\n        }\n\n        throw new PrestoException(AMBIGUOUS_FUNCTION_CALL, getErrorMessage(applicableFunctions));\n    }\n\n    private Optional<Signature> matchFunctionWithCoercion(Collection<? extends SqlFunction> candidates, List<TypeSignatureProvider> actualParameters)\n    {\n        return matchFunction(candidates, actualParameters, true);\n    }\n\n    private Optional<Signature> matchFunction(Collection<? extends SqlFunction> candidates, List<TypeSignatureProvider> parameters, boolean coercionAllowed)\n    {\n        List<ApplicableFunction> applicableFunctions = identifyApplicableFunctions(candidates, parameters, coercionAllowed);\n        if (applicableFunctions.isEmpty()) {\n            return Optional.empty();\n        }\n\n        if (coercionAllowed) {\n            applicableFunctions = selectMostSpecificFunctions(applicableFunctions, parameters);\n            checkState(!applicableFunctions.isEmpty(), \"at least single function must be left\");\n        }","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionSignatureMatcher.java#L112-L148","documentation":"FunctionSignatureMatcher.matchFunctionGeneric resolves a function call when several candidate overloads remain after deduplication and no single best candidate can be chosen. When multiple distinct applicable signatures tie, the matcher refuses to guess and throws AMBIGUOUS_FUNCTION_CALL, telling the developer to add explicit casts. The message says 'operator' but applies to generic function matching too.","triggerScenarios":"matchFunctionGeneric is given candidates where, after coercion and deduplication, more than one distinct signature applies equally — e.g. calling a function with argument types that two overloads can both accept with equal-cost coercions.","commonSituations":"Numeric literal or NULL argument that could coerce to multiple types (e.g. f(1) where f takes integer or double); overloaded UDFs with overlapping signatures; calls mixing types like decimal/double that both overloads accept after implicit coercion.","solutions":["Add explicit CASTs on ambiguous arguments so exactly one overload matches, e.g. CAST(x AS DOUBLE)","Inspect the 'Candidates are:' list in the message and pick the intended overload","Rename/redefine overlapping UDF overloads in your plugin to remove the ambiguity","Use typed literals (e.g. 1.0DOUBLE, DECIMAL '1.0') instead of untyped literals"],"exampleFix":"// before\nSELECT my_max(1, 2.5); -- AMBIGUOUS_FUNCTION_CALL\n// after\nSELECT my_max(CAST(1 AS DOUBLE), 2.5);","handlingStrategy":"try-catch","validationCode":"// Ensure arguments have unambiguous declared types before invoking overloaded functions\n// e.g. avoid untyped literals/NULL: use CAST(expr AS <targetType>) in generated SQL","typeGuard":null,"tryCatchPattern":"try { signature = matcher.matchFunctionGeneric(candidates, paramTypes); }\ncatch (PrestoException e) { if (AMBIGUOUS_FUNCTION_CALL.getCode() == e.getErrorCode()) { /* add casts and retry resolution */ } else throw e; }","preventionTips":["CAST ambiguous arguments (numbers, NULL, mixed numeric types) explicitly","Avoid defining UDF overloads with overlapping post-coercion signatures","Prefer typed literals (DECIMAL '1.0', DATE '...') in generated SQL","Read the candidate list in the message to pick the intended overload"],"tags":["presto","overload-resolution","sql"],"backgroundTag":"ambiguous-function-call","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"}