prestodb/presto · error · PinotException

PINOT_DECODE_ERROR

PINOT_DECODE_ERROR

Error message

Cannot decode double value from pinot %s

What it means

PinotUtils.parseDouble failed to convert a value returned by Pinot into a Presto double. The method special-cases NaN/infinity string tokens; any other unparseable value produces a NumberFormatException that is wrapped in this PINOT_DECODE_ERROR.

Source

Thrown at presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotUtils.java:95

                return TimestampUtils.toMillisSinceEpoch(value);
            }
        }
    }

    public static Double parseDouble(String value)
    {
        try {
            return Double.valueOf(value);
        }
        catch (NumberFormatException ne) {
            switch (value) {
                case PINOT_INFINITY:
                case PINOT_POSITIVE_INFINITY:
                    return PRESTO_INFINITY;
                case PINOT_NEGATIVE_INFINITY:
                    return PRESTO_NEGATIVE_INFINITY;
            }
            throw new PinotException(PINOT_DECODE_ERROR, Optional.empty(), "Cannot decode double value from pinot " + value, ne);
        }
    }
}

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Inspect the offending value in the message and clean/normalize the source column data in Pinot
  2. Cast or pre-format the column in SQL (e.g. date_trunc/CAST) so it parses as a number
  3. Extend the special-token handling in parseDouble for the unrecognized token (e.g. 'inf', '-Infinity')
  4. Check the timestamp format config (formatHint) for the column and fix the pattern

Example fix

// before
throw new PinotException(PINOT_DECODE_ERROR, Optional.empty(), "Cannot decode double value from pinot " + value, ne);
// after
if (value.equalsIgnoreCase("inf") || value.equalsIgnoreCase("+inf")) return PRESTO_INFINITY;
if (value.equalsIgnoreCase("-inf")) return PRESTO_NEGATIVE_INFINITY;
throw new PinotException(PINOT_DECODE_ERROR, Optional.empty(), "Cannot decode double value from pinot " + value, ne);
Defensive patterns

Strategy: validation

Validate before calling

// validate the value parses before the connector sees it (source-side check)
try { Double.parseDouble(value); }
catch (NumberFormatException e) {
  // normalize or reject at ingestion
  value = normalizeSpecialTokens(value); // 'inf' -> 'Infinity' etc.
}

Try / catch

try {
  rows = query.execute();
} catch (PinotException e) {
  if (PinotErrorCode.PINOT_DECODE_ERROR.toErrorCodeObject().equals(e.getErrorCode())) {
    log.error("Unparseable numeric/timestamp value: %s", e.getMessage());
    // rerun with the column cast to VARCHAR and decode client-side
    executeWithCast(originalQuery, offendingColumn, "VARCHAR");
  } else throw e;
}

Prevention

When it happens

Trigger: parseTimestamp (or another caller) passes a string that parseDouble cannot parse — e.g. non-numeric timestamp text, locale-formatted numbers, empty strings, or Pinot returning 'Infinity'/'NaN' variants not in the known token list.

Common situations: Timestamp columns stored as strings with non-numeric formats; Pinot returning special float tokens the connector doesn't recognize; data quality issues where NULL/garbage lands in a numeric column; connector/Pinot version drift in special-value serialization.

Related errors


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