{"id":"0ff99ff55dc829a9","repo":"apache/kafka","slug":"malformed-consumer-protocol-subscription","errorCode":null,"errorMessage":"Malformed consumer protocol subscription","messagePattern":"Malformed consumer protocol subscription","errorType":"exception","errorClass":"SchemaException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ConsumerProtocol.java","lineNumber":120,"sourceCode":"        try {\n            ConsumerProtocolSubscription data =\n                new ConsumerProtocolSubscription(new ByteBufferAccessor(buffer), version);\n\n            List<TopicPartition> ownedPartitions = new ArrayList<>();\n            for (ConsumerProtocolSubscription.TopicPartition tp : data.ownedPartitions()) {\n                for (Integer partition : tp.partitions()) {\n                    ownedPartitions.add(new TopicPartition(tp.topic(), partition));\n                }\n            }\n\n            return new Subscription(\n                data.topics(),\n                data.userData() != null ? data.userData().duplicate() : null,\n                ownedPartitions,\n                data.generationId(),\n                data.rackId() == null || data.rackId().isEmpty() ? Optional.empty() : Optional.of(data.rackId()));\n        } catch (RuntimeException e) {\n            throw new SchemaException(\"Malformed consumer protocol subscription\", e);\n        }\n    }\n\n    public static Subscription deserializeSubscription(final ByteBuffer buffer) {\n        return deserializeSubscription(buffer, deserializeVersion(buffer));\n    }\n\n    public static ConsumerProtocolSubscription deserializeConsumerProtocolSubscription(\n        final ByteBuffer buffer,\n        short version\n    ) {\n        version = checkSubscriptionVersion(version);\n\n        try {\n            return new ConsumerProtocolSubscription(new ByteBufferAccessor(buffer), version);\n        } catch (RuntimeException e) {\n            throw new SchemaException(\"Malformed consumer protocol subscription\", e);\n        }","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ConsumerProtocol.java#L102-L138","documentation":"Thrown by ConsumerProtocol.deserializeSubscription(ByteBuffer, short) when constructing a ConsumerProtocolSubscription from the buffer raises any RuntimeException. This wraps the underlying parse failure (typically BufferUnderflowException, IllegalArgumentException, or ArrayIndexOutOfBoundsException) into a SchemaException so callers see a single, well-typed error describing a structurally invalid subscription payload.","triggerScenarios":"A consumer group leader or broker sends a subscription ByteBuffer whose contents do not match the consumer protocol schema for the given version, or whose declared lengths exceed remaining bytes. Surfaced during SyncGroup/JoinGroup response handling on the broker-side assignor or when a client deserializes a peer's subscription.","commonSituations":"Mixed client versions where a newer client serializes subscription fields an older client cannot decode; custom assignor plugins producing non-conformant payloads; truncated network frames or corrupted stored group metadata being replayed during assignment.","solutions":["Inspect the cause (e.getCause()) of the SchemaException to identify the exact field that failed to parse.","Ensure all clients in the consumer group run a broker-and-protocol-compatible Kafka client version (subscriptions are forward-compatible but malformed payloads indicate a non-standard producer of the bytes).","Remove or fix any custom ConsumerPartitionAssignor that constructs subscription ByteBuffers by hand.","If the error appears after an upgrade, downgrade or roll forward all group members together so they share a schema."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// The body parse cannot be meaningfully pre-validated without decoding the schema,\n// so the only cheap pre-check is buffer sanity. Always run this before deserialize*.\nstatic void requireReadable(ByteBuffer buffer) {\n    if (buffer == null) throw new IllegalArgumentException(\"buffer == null\");\n    if (buffer.remaining() < Short.BYTES)\n        throw new IllegalArgumentException(\"subscription buffer too short to contain a version header\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Subscription sub = ConsumerProtocol.deserializeSubscription(buffer, version);\n} catch (org.apache.kafka.common.protocol.types.SchemaException e) {\n    // Subscription payload is malformed (bad topic string, truncated ownedPartitions, etc.).\n    // Most common when a non-consumer-protocol payload was sent on the group path,\n    // or when broker and client run incompatible consumer protocol versions.\n    log.warn(\"Rejecting malformed consumer protocol subscription\", e);\n    // trigger a fresh join/rebalance rather than retrying the same bytes.\n}","preventionTips":["Use only the official \"consumer\" protocol type with the built-in assignors unless you have explicitly implemented a custom one with matching serialization.","Keep client and broker versions aligned across the consumer group; mixed versions can produce payloads the older side cannot parse.","When subscribing, pass a non-null ByteBuffer only if your assignor expects userData; never hand arbitrary bytes as userData to a built-in assignor.","Log the failing version number alongside the exception to localize client/broker protocol mismatches."],"tags":["consumer","protocol","serialization","schema","subscription"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}