prestodb/presto · error · SQLException

Invalid timestamp from server:

Error message

Invalid timestamp from server: 

What it means

Thrown by PrestoResultSet.getTimestamp when a TIMESTAMP column value cannot be parsed by TIMESTAMP_FORMATTER.withZone(localTimeZone).parseMillis. The raw server string is included in the message alongside the wrapped IllegalArgumentException. It signals a value outside the expected ISO 'yyyy-MM-dd HH:mm:ss[.SSS]' format.

Source

Thrown at presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoResultSet.java:333

    {
        return getTimestamp(columnIndex, sessionTimeZone);
    }

    private Timestamp getTimestamp(int columnIndex, DateTimeZone localTimeZone)
            throws SQLException
    {
        Object value = column(columnIndex);
        if (value == null) {
            return null;
        }

        ColumnInfo columnInfo = columnInfo(columnIndex);
        if (columnInfo.getColumnTypeName().equalsIgnoreCase("timestamp")) {
            try {
                return new Timestamp(TIMESTAMP_FORMATTER.withZone(localTimeZone).parseMillis(String.valueOf(value)));
            }
            catch (IllegalArgumentException e) {
                throw new SQLException("Invalid timestamp from server: " + value, e);
            }
        }

        if (columnInfo.getColumnTypeName().equalsIgnoreCase("timestamp with time zone")) {
            try {
                return new Timestamp(TIMESTAMP_WITH_TIME_ZONE_FORMATTER.parseMillis(String.valueOf(value)));
            }
            catch (IllegalArgumentException e) {
                throw new SQLException("Invalid timestamp from server: " + value, e);
            }
        }

        throw new IllegalArgumentException("Expected column to be a timestamp type but is " + columnInfo.getColumnTypeName());
    }

    @Override
    public InputStream getAsciiStream(int columnIndex)
            throws SQLException

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Read the raw value from the exception message and verify it against the expected ISO format.
  2. Handle NULL first with wasNull() so an empty string is not fed to the parser.
  3. Align presto-jdbc driver version with the Presto server version.
  4. Normalize in SQL (CAST(col AS timestamp) or date_parse/format_datetime) before fetching.
  5. Fall back to getString and parse with a custom DateTimeFormatter matching the actual format.

Example fix

// before
Timestamp ts = rs.getTimestamp(4);
// after
String raw = rs.getString(4);
Timestamp ts = null;
if (raw != null) {
    try { ts = rs.getTimestamp(4); }
    catch (SQLException e) {
        long epoch = Long.parseLong(raw.trim()); // e.g. server sent epoch millis
        ts = new Timestamp(epoch);
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

String typeName = rs.getMetaData().getColumnTypeName(idx);
String raw = rs.getString(idx);
boolean safe = "timestamp".equalsIgnoreCase(typeName) && raw != null && raw.trim().matches("\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,9})?");

Type guard

boolean isTimestampColumn(ResultSet rs, int idx) throws SQLException {
    return "timestamp".equalsIgnoreCase(rs.getMetaData().getColumnTypeName(idx));
}

Try / catch

try {
    Timestamp ts = rs.getTimestamp(idx);
} catch (SQLException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Invalid timestamp from server:")) {
        String raw = rs.getString(idx);
        // custom parse (epoch millis, alternate formatter) or log-and-null
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling ResultSet.getTimestamp(columnIndex) on a 'timestamp' column whose value is empty, null-string, or non-ISO (e.g. '0000-00-00 00:00:00', epoch numbers, or locale-formatted dates).

Common situations: Custom connectors emitting epoch milliseconds or alternate formats; data polluted by other ETL tools; client/server version mismatch changing timestamp wire format; legacy zero dates surfaced through a Presto connector.

Related errors


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