prestodb/presto · error · SemanticException

INVALID_LITERAL

INVALID_LITERAL

Error message

'%s' is not a valid time literal

What it means

Presto raises this when a TIME literal's string value cannot be parsed to determine whether it carries a time zone. The literal keyword was accepted by the parser, but the value string is not a valid TIME format, so the analyzer cannot type the expression.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/ExpressionAnalyzer.java:943

            try {
                type = functionAndTypeResolver.getType(parseTypeSignature(node.getType()));
            }
            catch (IllegalArgumentException | UnknownTypeException e) {
                throw new SemanticException(TYPE_MISMATCH, node, "Unknown type: " + node.getType());
            }

            return setExpressionType(node, type);
        }

        @Override
        protected Type visitTimeLiteral(TimeLiteral node, StackableAstVisitorContext<Context> context)
        {
            boolean hasTimeZone;
            try {
                hasTimeZone = timeHasTimeZone(node.getValue());
            }
            catch (IllegalArgumentException e) {
                throw new SemanticException(INVALID_LITERAL, node, "'%s' is not a valid time literal", node.getValue());
            }
            Type type = hasTimeZone ? TIME_WITH_TIME_ZONE : TIME;
            return setExpressionType(node, type);
        }

        @Override
        protected Type visitTimestampLiteral(TimestampLiteral node, StackableAstVisitorContext<Context> context)
        {
            try {
                if (sqlFunctionProperties.isLegacyTimestamp()) {
                    parseTimestampLiteral(sqlFunctionProperties.getTimeZoneKey(), node.getValue());
                }
                else {
                    parseTimestampLiteral(node.getValue());
                }
            }
            catch (Exception e) {
                throw new SemanticException(INVALID_LITERAL, node, "'%s' is not a valid timestamp literal", node.getValue());

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Use the canonical format TIME 'HH:mm:ss[.SSS]' e.g. TIME '09:15:30.000'
  2. Include the offset if a time-zone value is intended: TIME '09:15:30.000 UTC' or '+08:00'
  3. Validate the literal string by running SELECT TIME '...' standalone before embedding in larger queries
  4. If the source data is not a literal, cast a VARCHAR column instead: CAST(col AS TIME)

Example fix

// before
SELECT TIME '9:15 AM';
// after
SELECT TIME '09:15:00.000';
Defensive patterns

Strategy: validation

Validate before calling

// Validate TIME literal format before embedding:
Pattern TIME_LIT = Pattern.compile("^\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,9})?)?( \\S+)?$");
boolean ok = TIME_LIT.matcher(value).matches();

Try / catch

try { run(sql); }
catch (PrestoException e) {
  if (e.getMessage() != null && e.getMessage().contains("not a valid time literal")) { /* reformat value */ }
  else throw e;
}

Prevention

When it happens

Trigger: Writing TIME 'not-a-time' or TIME '2020-01-01' (date only), or any malformed string inside TIME '...' in SQL.

Common situations: Hand-edited SQL with wrong literal format; copy-paste from other databases with different literal formats; missing quotes causing partial parse; locale-dependent formats like 12-hour times without AM/PM markers.

Related errors


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