{"record":{"id":"aa5d3adb65ebcb1e","repo":"apache/pulsar","slug":"invalid-messageidv5-data-bad-v4-length","errorCode":null,"errorMessage":"Invalid MessageIdV5 data: bad v4 length","messagePattern":"Invalid MessageIdV5 data: bad v4 length","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/MessageIdV5.java","lineNumber":273,"sourceCode":"    }\n\n    private static Map<Long, byte[]> serializeSegmentVector(Map<Long, MessageId> vector) {\n        Map<Long, byte[]> out = new HashMap<>(vector.size());\n        for (var entry : vector.entrySet()) {\n            out.put(entry.getKey(), entry.getValue().toByteArray());\n        }\n        return out;\n    }\n\n    static MessageIdV5 fromByteArray(byte[] data) throws IOException {\n        if (data == null || data.length < 12) {\n            throw new IOException(\"Invalid MessageIdV5 data: too short\");\n        }\n        ByteBuffer buf = ByteBuffer.wrap(data);\n        long segmentId = buf.getLong();\n        int v4Length = buf.getInt();\n        if (v4Length < 0 || v4Length > buf.remaining()) {\n            throw new IOException(\"Invalid MessageIdV5 data: bad v4 length\");\n        }\n        byte[] v4Bytes = new byte[v4Length];\n        buf.get(v4Bytes);\n        MessageId v4Id = MessageId.fromByteArray(v4Bytes);\n\n        // Section 3: position vector (single-topic / per-segment).\n        Map<Long, MessageId> positions = Map.of();\n        if (buf.hasRemaining()) {\n            positions = readSegmentVector(buf);\n        }\n\n        // Section 4: parent topic. Length -1 sentinel means \"absent\".\n        String parentTopic = null;\n        if (buf.hasRemaining()) {\n            int parentLen = buf.getInt();\n            if (parentLen >= 0) {\n                if (parentLen > buf.remaining()) {\n                    throw new IOException(\"Invalid MessageIdV5 data: bad parent-topic length\");","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/MessageIdV5.java#L255-L291","documentation":"After reading segmentId and a 4-byte v4 length, fromByteArray validates that the length is non-negative and does not exceed the remaining bytes; a value failing either check means the buffer is corrupt or misaligned, so it throws IOException('Invalid MessageIdV5 data: bad v4 length').","triggerScenarios":"Deserializing bytes not produced by MessageIdV5.toByteArray: wrong offset/framing, big-endian vs little-endian mismatch, a legacy v4 MessageId blob fed to the v5 parser, or truncated data where the declared length runs past the buffer.","commonSituations":"Mixing client versions sharing a message-id store; custom persistence writing/reading with differing byte order; an off-by-N offset when concatenating multiple ids into one blob.","solutions":["Regenerate the bytes with MessageIdV5.toByteArray from the same library version.","Verify byte order/framing of your storage layer matches the writer (ByteBuffer default big-endian).","Sanity-check the total blob length against the expected structure (8 + 4 + v4 + position vector).","Re-resolve the message id from the broker instead of trusting the stored blob."],"exampleFix":"// before\nbyte[] blob = legacyStore.read(key); // may be old v4 format\nMessageIdV5 id = MessageIdV5.fromByteArray(blob);\n// after\nbyte[] blob = legacyStore.read(key);\nMessageId id = isV5Format(blob) ? MessageIdV5.fromByteArray(blob)\n                                : MessageId.fromByteArray(blob);","handlingStrategy":"validation","validationCode":"if (data.length >= 12) {\n    int declaredLen = ByteBuffer.wrap(data, 8, 4).getInt();\n    if (declaredLen < 0 || 8 + 4 + declaredLen > data.length) {\n        throw new IOException(\"v4 length field inconsistent with blob size\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    MessageIdV5 id = MessageIdV5.fromByteArray(data);\n} catch (IOException e) {\n    log.warn(\"Bad v5 encoding ({}), attempting legacy v4 parse\", e.getMessage());\n    MessageId v4 = MessageId.fromByteArray(data);\n}","preventionTips":["Keep writer and reader on the same client version.","Use consistent byte order (big-endian) in custom persistence.","Persist a format marker to distinguish v4 vs v5 encodings before deserializing."],"tags":["deserialization","message-id","byte-buffer"],"backgroundTag":"invalid-message-id-data","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}