prestodb/presto · error · PrestoException
AMBIGUOUS_FUNCTION_CALL
AMBIGUOUS_FUNCTION_CALL
Error message
Could not choose a best candidate operator. Explicit type casts must be added. Candidates are:
What it means
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.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionSignatureMatcher.java:130
{
List<ApplicableFunction> applicableFunctions = identifyApplicableFunctions(candidates, actualParameters, false);
if (applicableFunctions.isEmpty()) {
return Optional.empty();
}
if (applicableFunctions.size() == 1) {
return Optional.of(applicableFunctions.stream().collect(onlyElement()).getBoundSignature());
}
List<Signature> deduplicatedSignatures = applicableFunctions.stream()
.map(applicableFunction -> applicableFunction.boundSignature)
.distinct()
.collect(toImmutableList());
if (deduplicatedSignatures.size() == 1) {
return Optional.of(deduplicatedSignatures.stream().collect(onlyElement()));
}
throw new PrestoException(AMBIGUOUS_FUNCTION_CALL, getErrorMessage(applicableFunctions));
}
private Optional<Signature> matchFunctionWithCoercion(Collection<? extends SqlFunction> candidates, List<TypeSignatureProvider> actualParameters)
{
return matchFunction(candidates, actualParameters, true);
}
private Optional<Signature> matchFunction(Collection<? extends SqlFunction> candidates, List<TypeSignatureProvider> parameters, boolean coercionAllowed)
{
List<ApplicableFunction> applicableFunctions = identifyApplicableFunctions(candidates, parameters, coercionAllowed);
if (applicableFunctions.isEmpty()) {
return Optional.empty();
}
if (coercionAllowed) {
applicableFunctions = selectMostSpecificFunctions(applicableFunctions, parameters);
checkState(!applicableFunctions.isEmpty(), "at least single function must be left");
}View on GitHub (pinned to 55bb57d202)
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
Example fix
// before SELECT my_max(1, 2.5); -- AMBIGUOUS_FUNCTION_CALL // after SELECT my_max(CAST(1 AS DOUBLE), 2.5);
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure arguments have unambiguous declared types before invoking overloaded functions // e.g. avoid untyped literals/NULL: use CAST(expr AS <targetType>) in generated SQL
Try / catch
try { signature = matcher.matchFunctionGeneric(candidates, paramTypes); }
catch (PrestoException e) { if (AMBIGUOUS_FUNCTION_CALL.getCode() == e.getErrorCode()) { /* add casts and retry resolution */ } else throw e; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- FUNCTION_NOT_FOUND
- INVALID_TABLE_PROPERTY
- Invalid time from server:
- Expected column to be a time type but is
- Invalid timestamp from server:
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/dcc9645208448428.
Report an issue: GitHub.