prestodb/presto · error · ParsingException
Duplicate language clause: %s
Error message
Duplicate language clause: %s
What it means
AstBuilder.visitCreateFunction (routine characteristics loop) throws ParsingException when a CREATE FUNCTION statement specifies the LANGUAGE characteristic more than once. SQL routine characteristics must be unique, so a second LANGUAGE clause is rejected at parse time.
Source
Thrown at presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java:3064
throw new IllegalArgumentException("Unsupported type specification: " + type.getText());
}
private SqlParameterDeclaration getParameterDeclarations(SqlBaseParser.SqlParameterDeclarationContext context)
{
return new SqlParameterDeclaration((Identifier) visit(context.identifier()), getType(context.type()));
}
private RoutineCharacteristics getRoutineCharacteristics(SqlBaseParser.RoutineCharacteristicsContext context)
{
Language language = null;
Determinism determinism = null;
NullCallClause nullCallClause = null;
for (SqlBaseParser.RoutineCharacteristicContext characteristic : context.routineCharacteristic()) {
if (characteristic.language() != null) {
if (language != null) {
throw new ParsingException(format("Duplicate language clause: %s", characteristic.language().getText()), getLocation(characteristic.language()));
}
if (characteristic.language().SQL() != null) {
language = Language.SQL;
}
else {
language = new Language(((Identifier) visit(characteristic.language().identifier())).getValue());
}
}
else if (characteristic.determinism() != null) {
if (determinism != null) {
throw new ParsingException(format("Duplicate determinism characteristics: %s", characteristic.determinism().getText()), getLocation(characteristic.determinism()));
}
determinism = characteristic.determinism().NOT() == null ? DETERMINISTIC : NOT_DETERMINISTIC;
}
else if (characteristic.nullCallClause() != null) {
if (nullCallClause != null) {
throw new ParsingException(format("Duplicate null-call clause: %s", characteristic.nullCallClause().getText()), getLocation(characteristic.nullCallClause()));
}View on GitHub (pinned to 55bb57d202)
Solutions
- Remove all but one LANGUAGE clause from the function definition.
- Deduplicate characteristics in SQL-generating code.
- Pre-validate the characteristic list for repeated LANGUAGE keywords before parsing/executing.
- Fix templates so each characteristic is emitted at most once.
Example fix
// before CREATE FUNCTION f() RETURNS int LANGUAGE SQL LANGUAGE SQL RETURN 1; // after CREATE FUNCTION f() RETURNS int LANGUAGE SQL RETURN 1;
Defensive patterns
Strategy: validation
Validate before calling
// dedupe routine characteristics before parsing
treeSet.add() ; // e.g. collect LANGUAGE clauses
long langs = sqlChars.stream().filter(c -> c.matches("(?i)LANGUAGE\\s+")).count();
if (langs > 1) throw new IllegalArgumentException("Duplicate LANGUAGE clause"); Type guard
boolean hasDuplicateCharacteristic(String sql, String keyword) {
return Pattern.compile("(?i)\\b" + keyword + "\\b").splitAsStream(sql).count() > 2;
} Try / catch
try {
parser.createStatement(sql);
} catch (ParsingException e) {
if (e.getMessage().startsWith("Duplicate language clause")) {
throw new IllegalArgumentException("Remove extra LANGUAGE clauses from function DDL", e);
}
throw e;
} Prevention
- Generate characteristics from a Set so each clause appears once.
- Have SQL templates replace rather than append characteristics.
- Validate function DDL in unit tests.
When it happens
Trigger: Parsing 'CREATE FUNCTION ... LANGUAGE SQL LANGUAGE SQL ...' or any statement with two LANGUAGE characteristics in the routine_characteristic list.
Common situations: Generated SQL that appends characteristics repeatedly, templating bugs that emit the clause per parameter/version, or hand-written functions copied from dialects with repeated clauses.
Related errors
- Duplicate determinism characteristics: %s
- Duplicate null-call clause: %s
- WARNING_AS_ERROR
- GENERIC_USER_ERROR
- Unsupported EXPLAIN format:
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/40860ec4fdced73e.
Report an issue: GitHub.