prestodb/presto · error · ParsingException

identifiers must not start with a digit; surround the identi

Error message

identifiers must not start with a digit; surround the identifier with double quotes

What it means

Identifiers may not begin with a digit in Presto's grammar. When the lexer produces a DIGIT_IDENTIFIER token, PostProcessor.exitDigitIdentifier throws a ParsingException instructing the user to quote the identifier with double quotes.

Source

Thrown at presto-parser/src/main/java/com/facebook/presto/sql/parser/SqlParser.java:229

            }
        }

        @Override
        public void exitBackQuotedIdentifier(SqlBaseParser.BackQuotedIdentifierContext context)
        {
            Token token = context.BACKQUOTED_IDENTIFIER().getSymbol();
            throw new ParsingException(
                    "backquoted identifiers are not supported; use double quotes to quote identifiers",
                    null,
                    token.getLine(),
                    token.getCharPositionInLine());
        }

        @Override
        public void exitDigitIdentifier(SqlBaseParser.DigitIdentifierContext context)
        {
            Token token = context.DIGIT_IDENTIFIER().getSymbol();
            throw new ParsingException(
                    "identifiers must not start with a digit; surround the identifier with double quotes",
                    null,
                    token.getLine(),
                    token.getCharPositionInLine());
        }

        @Override
        public void exitNonReserved(SqlBaseParser.NonReservedContext context)
        {
            // we can't modify the tree during rule enter/exit event handling unless we're dealing with a terminal.
            // Otherwise, ANTLR gets confused an fires spurious notifications.
            if (!(context.getChild(0) instanceof TerminalNode)) {
                int rule = ((ParserRuleContext) context.getChild(0)).getRuleIndex();
                throw new AssertionError("nonReserved can only contain tokens. Found nested rule: " + ruleNames.get(rule));
            }

            // replace nonReserved words with IDENT tokens
            context.getParent().removeLastChild();

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Double-quote the identifier: "1st_col"
  2. Rename the column/identifier so it starts with a letter or underscore
  3. Escape numeric-leading names at schema design time

Example fix

// before
String sql = "SELECT 2023_data FROM t";
// after
String sql = "SELECT \"2023_data\" FROM t";
Defensive patterns

Strategy: validation

Validate before calling

// Quote identifiers that start with a digit before embedding in SQL
if (identifier.matches("\\d.*")) {
    identifier = '"' + identifier.replace("\"", "\"\"") + '"';
}

Type guard

boolean isDigitLeadingIdentifier(String id) {
    return id != null && !id.isEmpty() && Character.isDigit(id.charAt(0));
}

Try / catch

try {
    return sqlParser.createStatement(sql);
} catch (ParsingException e) {
    if (e.getMessage() != null && e.getMessage().contains("must not start with a digit")) {
        throw new IdentifierQuotingRequiredException(e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Parsing SQL with a bare token starting with a digit used as an identifier, e.g. SELECT 1st_col FROM t or a column named 2023_data unquoted.

Common situations: Columns auto-named after years/numbers in spreadsheets or ETL output, generated column aliases like 1x, queries against schemas with numeric-leading names.

Related errors


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