{"record":{"id":"9b16d55079b666b4","repo":"prestodb/presto","slug":"error-decoding-key-planhash-which-was-of-type-stri","errorCode":null,"errorMessage":"Error decoding key planHash which was of type String","messagePattern":"Error decoding key planHash which was of type String","errorType":"exception","errorClass":"RedisProviderSerdeException","httpStatus":null,"severity":"error","filePath":"redis-hbo-provider/src/main/java/com/facebook/presto/statistic/HistoricalStatisticsSerde.java","lineNumber":46,"sourceCode":"import java.nio.charset.StandardCharsets;\n\n/**\n * Redis codec implementation for string keys and HistoricalPlanStatistics values.\n */\npublic class HistoricalStatisticsSerde\n        implements RedisCodec<String, HistoricalPlanStatistics>\n{\n    private static final int ESTIMATED_BUFFER_SIZE_BYTES = 100 * 1024;\n    private final ThriftCodecManager thriftCodecManager = new ThriftCodecManager();\n\n    @Override\n    public String decodeKey(ByteBuffer bytes)\n    {\n        if (bytes.hasArray()) {\n            return StandardCharsets.UTF_8.decode(bytes).toString();\n        }\n        else {\n            throw new RedisProviderSerdeException(\"Error decoding key planHash which was of type String\");\n        }\n    }\n\n    @Override\n    public ByteBuffer encodeKey(String key)\n    {\n        return ByteBuffer.wrap(key.getBytes(StandardCharsets.UTF_8));\n    }\n\n    @Override\n    public ByteBuffer encodeValue(HistoricalPlanStatistics historicalPlanStatistics)\n    {\n        ThriftCodec<HistoricalPlanStatistics> writeCodec = thriftCodecManager.getCodec(HistoricalPlanStatistics.class);\n        SliceOutput dynamicSliceOutput = new DynamicSliceOutput(ESTIMATED_BUFFER_SIZE_BYTES);\n        try {\n            ThriftProtocolUtils.write(historicalPlanStatistics, writeCodec, Protocol.BINARY, dynamicSliceOutput);\n            return ByteBuffer.wrap(dynamicSliceOutput.slice().getBytes());\n        }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/redis-hbo-provider/src/main/java/com/facebook/presto/statistic/HistoricalStatisticsSerde.java#L28-L64","documentation":"HistoricalStatisticsSerde.decodeKey can only decode a UTF-8 String key when the ByteBuffer is backed by a heap array (hasArray() == true). If the buffer is a direct/off-heap or otherwise non-array-backed ByteBuffer, it throws RedisProviderSerdeException because the UTF_8.decode path cannot be applied directly.","triggerScenarios":"decodeKey is called with a direct ByteBuffer (allocated via allocateDirect) or a sliced/duplicated buffer with no accessible backing array, e.g. a key read from the Redis client into direct memory.","commonSituations":"Redis provider returns direct ByteBuffers for performance; a custom serde pipeline swaps heap buffers for direct ones; a library upgrade changes how ByteBuffers are produced upstream.","solutions":["Add a fallback that copies direct buffer contents into a heap array before UTF-8 decoding: ByteBuffer.wrap(new byte[bytes.remaining()]).put(bytes.duplicate())","Ensure the producer of the key ByteBuffer allocates on-heap (ByteBuffer.allocate / wrap)","Update the Redis provider/serde integration so keys are passed as array-backed buffers"],"exampleFix":"// before\nif (bytes.hasArray()) {\n    return StandardCharsets.UTF_8.decode(bytes).toString();\n}\nthrow new RedisProviderSerdeException(\"Error decoding key planHash which was of type String\");\n// after\nByteBuffer dup = bytes.duplicate();\nbyte[] array = new byte[dup.remaining()];\ndup.get(array);\nreturn new String(array, StandardCharsets.UTF_8);","handlingStrategy":"try-catch","validationCode":"boolean isDecodable(ByteBuffer buf) {\n    return buf != null && buf.hasArray();\n}","typeGuard":"boolean isHeapByteBuffer(ByteBuffer buf) {\n    return buf != null && buf.hasArray();\n}","tryCatchPattern":"try {\n    key = serde.decodeKey(buffer);\n} catch (RedisProviderSerdeException e) {\n    ByteBuffer dup = buffer.duplicate();\n    byte[] arr = new byte[dup.remaining()];\n    dup.get(arr);\n    key = new String(arr, StandardCharsets.UTF_8);\n}","preventionTips":["Prefer on-heap ByteBuffers (allocate/wrap) when producing keys for this serde","Add a hasArray() pre-check before calling decodeKey","Keep a copy-based fallback in the caller for direct buffers"],"tags":["redis","serialization","bytebuffer","hbo"],"backgroundTag":"bytebuffer-decode-failure","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}