prestodb/presto · error · IllegalArgumentException
Original function call and substitute must both be specified
Error message
Original function call and substitute must both be specified, %s.
What it means
The Verifier's function-call substitution config (function-call-substitutes) expects each substitute entry to be a spec of exactly two parts: the original function call and the replacement expression, separated by '/'. When an entry does not split into exactly two slash-delimited parts, validateAndConstructFunctionCallSubstituteMap throws this IllegalArgumentException. It is a fail-fast config validation error.
Source
Thrown at presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/FunctionCallRewriter.java:98
return Optional.empty();
}
checkState(typeManager instanceof FunctionAndTypeManager, "FunctionAndTypeManager is required for FunctionCallRewriter.");
return Optional.of(new FunctionCallRewriter(functionCallSubstitutes, (FunctionAndTypeManager) typeManager));
}
public static Multimap<String, FunctionCallSubstitute> validateAndConstructFunctionCallSubstituteMap(String functionCallSubstitutes)
{
ImmutableMultimap.Builder<String, FunctionCallSubstitute> map = ImmutableMultimap.builder();
if (functionCallSubstitutes == null) {
return map.build();
}
Splitter commaSplitter = Splitter.on("/,/").omitEmptyStrings().trimResults();
Splitter slashSplitter = Splitter.on('/').omitEmptyStrings().trimResults();
for (String substitute : commaSplitter.split(functionCallSubstitutes)) {
List<String> specs = slashSplitter.splitToList(substitute);
if (specs.size() != 2) {
throw new IllegalArgumentException(String.format("Original function call and substitute must both be specified, %s.", substitute));
}
Expression originalExpression = parseOriginalFunctionCall(specs.get(0));
Expression substituteExpression = parseSubstituteExpression(specs.get(1));
if (originalExpression instanceof FunctionCall) {
FunctionCall originalFunction = (FunctionCall) originalExpression;
map.put(originalFunction.getName().getSuffix(), new FunctionCallSubstitute(originalExpression, substituteExpression));
}
else if (originalExpression instanceof CurrentTime) {
CurrentTime originalFunction = (CurrentTime) originalExpression;
map.put(originalFunction.getFunction().getName(), new FunctionCallSubstitute(originalExpression, substituteExpression));
}
}
return map.build();
}
public RewriterResult rewrite(Statement root)View on GitHub (pinned to 55bb57d202)
Solutions
- Fix the config entry so it has exactly one '/' separating original and substitute, e.g. 'original_fn(x)/replacement_fn(x)'
- Escape or remove any literal '/' characters appearing inside function arguments in the spec
- Split complex entries: each comma-separated element must contain exactly one pair; move extra mappings to their own entry
Example fix
// before (config value) functionCallSubstitutes = myfunc(x) // after (config value) functionCallSubstitutes = myfunc(x)/myfunc_new(x)
Defensive patterns
Strategy: validation
Validate before calling
// Validate each comma-separated entry has exactly one '/' before configuring
GuavaSplitter.on(",").omitEmptyStrings().trimResults().split(configValue).forEach(entry -> {
long slashes = entry.chars().filter(c -> c == '/').count();
if (slashes != 1) {
throw new IllegalArgumentException("Entry must be 'original/substitute': " + entry);
}
}); Type guard
boolean isValidSubstituteSpec(String entry) {
return entry != null && entry.indexOf('/') == entry.lastIndexOf('/') && entry.indexOf('/') >= 0;
} Try / catch
try {
rewriter = FunctionCallRewriter.getInstance(functionCallSubstitutes, typeManager);
} catch (IllegalArgumentException e) {
LOG.error("Bad function-call-substitutes config, skipping rewrites: %s", e.getMessage());
rewriter = Optional.empty();
} Prevention
- Keep function arguments free of '/' or document how the spec separator collides
- Lint verifier config entries for exactly one '/' per entry at startup
- Keep each original/substitute pair as its own comma-separated entry
When it happens
Trigger: Passing a functionCallSubstitutes config string where any comma-separated entry contains zero or more than one '/' separator, e.g. 'myfunc(x)' (no substitute) or 'myfunc(x)/abs(x)/extra' (three parts). Note empty segments are omitted, so a double slash yields one part and also fails.
Common situations: Typos in the verifier config properties file; forgetting the second half of a substitute; using a literal '/' inside a function argument without realizing it is the spec separator; copy-pasting entries that contain multiple slashes.
Related errors
- app-secret not provided in " + secretFile
- id is empty
- Role must be present for the selected role type:
- catalog must be present if schema is present
- Function call spec %s is not in a valid format.
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/30af37ea3e01a321.
Report an issue: GitHub.