{"record":{"id":"f8c299da86422b98","repo":"apache/kafka","slug":"topology-description-is-missing-despite-status-ava","errorCode":null,"errorMessage":"Topology description is missing despite status AVAILABLE","messagePattern":"Topology description is missing despite status AVAILABLE","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/admin/internals/DescribeStreamsGroupsHandler.java","lineNumber":236,"sourceCode":"                topicInfo.partitions(),\n                topicInfo.replicationFactor(),\n                topicInfo.topicConfigs().stream().collect(Collectors.toMap(\n                    StreamsGroupDescribeResponseData.KeyValue::key,\n                    StreamsGroupDescribeResponseData.KeyValue::value\n                ))\n            )\n        ));\n    }\n\n    private Optional<StreamsGroupTopologyDescription> convertTopologyDescription(\n            final StreamsGroupTopologyDescriptionStatus status,\n            final StreamsGroupDescribeResponseData.TopologyDescription topologyDescription) {\n\n        if (status != StreamsGroupTopologyDescriptionStatus.AVAILABLE) {\n            return Optional.empty();\n        }\n        if (topologyDescription == null) {\n            throw new IllegalStateException(\"Topology description is missing despite status AVAILABLE\");\n        }\n        final List<StreamsGroupTopologyDescription.Subtopology> subtopologies = topologyDescription.subtopologies().stream()\n            .map(this::convertTopologySubtopology)\n            .collect(Collectors.toList());\n        final List<StreamsGroupTopologyDescription.GlobalStore> globalStores = topologyDescription.globalStores().stream()\n            .map(this::convertGlobalStore)\n            .collect(Collectors.toList());\n        return Optional.of(new StreamsGroupTopologyDescription(subtopologies, globalStores));\n    }\n\n    private StreamsGroupTopologyDescription.Subtopology convertTopologySubtopology(\n            final StreamsGroupDescribeResponseData.TopologyDescriptionSubtopology subtopology) {\n        final Map<String, Set<String>> predecessors = reconstructPredecessors(subtopology.nodes());\n        final List<StreamsGroupTopologyDescription.Node> nodes = subtopology.nodes().stream()\n            .map(node -> convertTopologyNode(node, predecessors))\n            .collect(Collectors.toList());\n        return new StreamsGroupTopologyDescription.Subtopology(subtopology.subtopologyId(), nodes);\n    }","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/apache/kafka/blob/996fb4585aa1bcc8980b0e1b8d6b168b986cd979/clients/src/main/java/org/apache/kafka/clients/admin/internals/DescribeStreamsGroupsHandler.java#L218-L254","documentation":"Thrown by DescribeStreamsGroupsHandler.convertTopologyDescription when the broker reported StreamsGroupTopologyDescriptionStatus.AVAILABLE but the topologyDescription field of the response is null. This is an IllegalStateException because it represents a contract violation by the broker: AVAILABLE implies a non-null payload. Clients cannot recover the missing description.","triggerScenarios":"Receiving a StreamsGroupDescribeResponse where status == AVAILABLE but topologyDescription == null. Emitted from admin.describeStreamsGroups when the response is parsed.","commonSituations":"Broker bug or version skew during a rolling upgrade; a corrupt or partially-serialized response; an experimental/unstable broker build that omits the payload.","solutions":["Upgrade or roll back the broker so client and server agree on the response schema.","File a broker-side bug; this is not a client configuration issue.","Catch IllegalStateException from describeStreamsGroups and degrade gracefully (e.g. report topology unavailable)."],"exampleFix":"// before\nMap<String, StreamsGroupDescription> r =\n    admin.describeStreamsGroups(List.of(g)).all().get();\n\n// after\ntry {\n    Map<String, StreamsGroupDescription> r =\n        admin.describeStreamsGroups(List.of(g)).all().get();\n} catch (ExecutionException e) {\n    if (e.getCause() instanceof IllegalStateException) {\n        log.warn(\"Broker returned inconsistent streams topology for {}; reporting unavailable\", g, e);\n    } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Cannot pre-validate broker response; mitigate by ensuring version alignment\nassert clientVersionIsAtLeast(brokerVersion);","typeGuard":null,"tryCatchPattern":"try {\n    return admin.describeStreamsGroups(groups).all().get();\n} catch (ExecutionException e) {\n    if (e.getCause() instanceof IllegalStateException) {\n        log.warn(\"Inconsistent streams describe response; possible broker bug or version skew\", e);\n        return Collections.emptyMap();\n    }\n    throw e;\n}","preventionTips":["Align client and broker versions in your deployment pipeline.","Treat describeStreamsGroups as best-effort and degrade gracefully when it fails.","Report recurring IllegalStateException occurrences to the broker maintainers."],"tags":["admin-client","streams","wire-protocol","illegal-state","version-mismatch","broker-bug"],"backgroundTag":null,"analyzedSha":"996fb4585aa1bcc8980b0e1b8d6b168b986cd979","analyzedAt":"2026-08-11T22:03:28.655Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}