prestodb/presto · error · RedisProviderSerdeException
Error decoding historicalPlanStatistics value
Error message
Error decoding historicalPlanStatistics value
What it means
HistoricalStatisticsSerde is a Redis codec that deserializes Redis byte values into HistoricalPlanStatistics using the Drift Thrift codec with the BINARY protocol. When the underlying ThriftProtocolUtils.read call fails with a ThriftProtocolException, it is wrapped in a RedisProviderSerdeException with this message. This means the bytes read from Redis are not a valid Thrift-BINARY-encoded HistoricalPlanStatistics payload.
Source
Thrown at redis-hbo-provider/src/main/java/com/facebook/presto/statistic/HistoricalStatisticsSerde.java:78
SliceOutput dynamicSliceOutput = new DynamicSliceOutput(ESTIMATED_BUFFER_SIZE_BYTES);
try {
ThriftProtocolUtils.write(historicalPlanStatistics, writeCodec, Protocol.BINARY, dynamicSliceOutput);
return ByteBuffer.wrap(dynamicSliceOutput.slice().getBytes());
}
catch (ThriftProtocolException e) {
throw new RedisProviderSerdeException("Error encoding historicalPlanStatistics value", e);
}
}
@Override
public HistoricalPlanStatistics decodeValue(ByteBuffer byteBuffer)
{
ThriftCodec<HistoricalPlanStatistics> readCodec = thriftCodecManager.getCodec(HistoricalPlanStatistics.class);
try {
return ThriftProtocolUtils.read(readCodec, Protocol.BINARY, Slices.wrappedBuffer(byteBuffer).getInput());
}
catch (ThriftProtocolException e) {
throw new RedisProviderSerdeException("Error decoding historicalPlanStatistics value", e);
}
}
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Flush the Redis keyspace (or delete the offending plan-hash keys) so stale/incompatible encoded values are repopulated by encodeValue with the current schema.
- Verify values were written with Protocol.BINARY via ThriftProtocolUtils.write and not by another serializer/protocol; re-encode with the current writer.
- Check for a Presto/Drift version skew between the writer and reader clusters and align versions so the Thrift schema matches.
- Inspect the wrapped ThriftProtocolException (getCause) for the exact decode offset/field to confirm corruption vs schema mismatch.
- Add entry validation (try decode, skip/log on RedisProviderSerdeException) so a single bad entry does not break statistics collection.
Example fix
// before
return ThriftProtocolUtils.read(readCodec, Protocol.BINARY, Slices.wrappedBuffer(byteBuffer).getInput());
// after
if (byteBuffer == null || !byteBuffer.hasRemaining()) {
return null; // skip empty/invalid Redis value instead of failing decode
}
return ThriftProtocolUtils.read(readCodec, Protocol.BINARY, Slices.wrappedBuffer(byteBuffer).getInput()); Defensive patterns
Strategy: try-catch
Validate before calling
// validate before trusting Redis bytes
if (byteBuffer == null || !byteBuffer.hasRemaining()) {
throw new IllegalArgumentException("Empty value for historicalPlanStatistics");
}
HistoricalPlanStatistics stats;
try {
stats = ThriftProtocolUtils.read(readCodec, Protocol.BINARY, Slices.wrappedBuffer(byteBuffer).getInput());
}
catch (ThriftProtocolException e) {
throw new RedisProviderSerdeException("Error decoding historicalPlanStatistics value", e);
} Type guard
private static boolean isDecodableValue(ByteBuffer buf)
{
return buf != null && buf.hasRemaining();
} Try / catch
try {
HistoricalPlanStatistics stats = serde.decodeValue(byteBuffer);
useStats(stats);
}
catch (RedisProviderSerdeException e) {
log.warn(e, "Skipping undecodable historicalPlanStatistics entry (cause: %s)", e.getCause());
redis.delete(key); // drop corrupt/stale entry so it is re-encoded
} Prevention
- Always write values with the matching encoder (encodeValue, Protocol.BINARY) rather than hand-crafting bytes
- Clear or version-key the Redis namespace when upgrading Presto/Drift so old-schema entries are not decoded by new code
- Wrap decode calls per entry so one corrupt key cannot break the whole statistics flow
- Monitor and alert on RedisProviderSerdeException rates to catch schema skew early
- Use a version prefix in Redis keys to distinguish schema generations
When it happens
Trigger: Redis returns bytes that cannot be parsed as a Thrift BINARY encoding of HistoricalPlanStatistics: truncated/corrupted records, values written with a different Thrift protocol (e.g. COMPACT) or an incompatible HistoricalPlanStatistics schema version, stale entries persisted by an older Presto build, or manual writes to the Redis keyspace by another tool.
Common situations: Upgrading Presto where the HistoricalPlanStatistics Thrift schema changed but old Redis entries remain; pointing a cluster at a Redis DB populated by a different component or protocol; Redis data corruption or partial writes; keys written by a test/other service using a non-Binary protocol.
Related errors
- NOT_SUPPORTED
- Type %s is not supported
- Role must be present for the selected role type:
- Expected a Class type for javaType, but got:
- Can not deserialize the data
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/d50d2584c22f3373.
Report an issue: GitHub.