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
- Use the canonical format TIME 'HH:mm:ss[.SSS]' e.g. TIME '09:15:30.000'
- Include the offset if a time-zone value is intended: TIME '09:15:30.000 UTC' or '+08:00'
- Validate the literal string by running SELECT TIME '...' standalone before embedding in larger queries
- 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
- Always emit TIME literals as HH:mm:ss[.fraction] (24-hour)
- Append the zone only when intended (TIME WITH TIME ZONE)
- Normalize 12-hour input to 24-hour before building SQL
- Test literals standalone before embedding in large queries
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.