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

  1. Remove all but one LANGUAGE clause from the function definition.
  2. Deduplicate characteristics in SQL-generating code.
  3. Pre-validate the characteristic list for repeated LANGUAGE keywords before parsing/executing.
  4. 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

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


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/40860ec4fdced73e. Report an issue: GitHub.