{"id":"7334cc589596c6e8","repo":"apache/kafka","slug":"unexpected-error-fetching-metadata-for-topic-top","errorCode":null,"errorMessage":"Unexpected error fetching metadata for topic ${topic}","messagePattern":"Unexpected error fetching metadata for topic (.+?)","errorType":"exception","errorClass":"KafkaException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/TopicMetadataFetcher.java","lineNumber":136,"sourceCode":"                    // if there were errors, we need to check whether they were fatal or whether\n                    // we should just retry\n\n                    log.debug(\"Topic metadata fetch included errors: {}\", errors);\n\n                    for (Map.Entry<String, Errors> errorEntry : errors.entrySet()) {\n                        String topic = errorEntry.getKey();\n                        Errors error = errorEntry.getValue();\n\n                        if (error == Errors.INVALID_TOPIC_EXCEPTION)\n                            throw new InvalidTopicException(\"Topic '\" + topic + \"' is invalid\");\n                        else if (error == Errors.UNKNOWN_TOPIC_OR_PARTITION)\n                            // if a requested topic is unknown, we just continue and let it be absent\n                            // in the returned map\n                            continue;\n                        else if (error.exception() instanceof RetriableException)\n                            shouldRetry = true;\n                        else\n                            throw new KafkaException(\"Unexpected error fetching metadata for topic \" + topic,\n                                    error.exception());\n                    }\n                }\n\n                if (!shouldRetry) {\n                    HashMap<String, List<PartitionInfo>> topicsPartitionInfos = new HashMap<>();\n                    for (String topic : cluster.topics())\n                        topicsPartitionInfos.put(topic, cluster.partitionsForTopic(topic));\n                    return topicsPartitionInfos;\n                }\n            }\n\n            timer.sleep(retryBackoff.backoff(attempts++));\n        } while (timer.notExpired());\n\n        throw new TimeoutException(\"Timeout expired while fetching topic metadata\");\n    }\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/TopicMetadataFetcher.java#L118-L154","documentation":"Thrown as a generic KafkaException by TopicMetadataFetcher.getTopicMetadata for any non-retriable, non-INVALID_TOPIC, non-UNKNOWN_TOPIC_OR_PARTITION error returned by the broker in MetadataResponse.errors(). It is the catch-all branch when none of the recognized error codes match, wrapping the underlying error.exception() as the cause. Treat the wrapped cause as authoritative for diagnosis.","triggerScenarios":"Broker returns an unexpected Errors code in the per-topic error map during a MetadataResponse (e.g. TOPIC_AUTHORIZATION_FAILED not surfaced via unauthorizedTopics, CLUSTER_AUTHORIZATION_FAILED, INVALID_RECORD, or a future/unknown error code from a newer broker). Also possible if the error map contains a code the client does not branch on.","commonSituations":"Client/broker version skew where a newer broker emits an error code the older client does not handle explicitly; non-standard broker or proxy translating errors; rare authorization paths that don't populate unauthorizedTopics; corrupted/translated metadata responses from a sidecar.","solutions":["Inspect the wrapped cause (exception.getCause()) — the underlying org.apache.kafka.common.protocol.Errors code is the real signal.","Align client and broker versions to avoid unrecognized error codes (check BrokerProtocolCompatibility / apiVersions response).","If the cause is authorization-related, follow the TopicAuthorizationException remediation (grant ACLs).","Enable DEBUG on org.apache.kafka.clients.consumer.internals.TopicMetadataFetcher to log the full error map ('Topic metadata fetch included errors: ...')."],"exampleFix":"// before\ntry {\n    consumer.partitionsFor(topic);\n} catch (KafkaException e) {\n    log.error(\"metadata failed\", e); // cause is hidden\n}\n\n// after\ntry {\n    consumer.partitionsFor(topic);\n} catch (KafkaException e) {\n    Throwable cause = e.getCause() != null ? e.getCause() : e;\n    log.error(\"metadata failed; broker error code: {}\", cause.getClass().getSimpleName(), cause);\n}","handlingStrategy":"try-catch","validationCode":"// No reliable client-side precheck for arbitrary broker-side metadata errors.\n// Best mitigation: keep client lib version compatible with broker version, and preflight reachability:\ntry (java.net.Socket s = new java.net.Socket()) {\n    s.connect(new java.net.InetSocketAddress(bootstrapHost, bootstrapPort), 2000);\n}","typeGuard":"import org.apache.kafka.common.KafkaException;\n\n/** True iff a throwable is the 'Unexpected error fetching metadata' wrapper with a classifiable cause. */\nstatic boolean isUnexpectedMetadataError(Throwable t) {\n    if (!(t instanceof KafkaException)) return false;\n    String m = t.getMessage();\n    return m != null && m.startsWith(\"Unexpected error fetching metadata for topic\");\n}","tryCatchPattern":"try {\n    consumer.partitionsFor(topic);\n} catch (org.apache.kafka.common.KafkaException e) {\n    Throwable cause = e.getCause();\n    log.error(\"Unexpected metadata error for {}; cause={}:{}\", topic,\n        cause == null ? null : cause.getClass().getName(),\n        cause == null ? null : cause.getMessage(), e);\n    // classify: if cause is retriable (e.g. LeaderNotSelected) -> backoff retry; else -> escalate\n    if (cause instanceof org.apache.kafka.common.errors.RetriableException) { /* retry */ }\n    else throw e;\n}","preventionTips":["Log and inspect getCause() — the wrapper hides the real broker error.","Keep the kafka-clients version within the supported matrix for your broker version.","Surface the underlying cause to monitoring rather than the generic wrapper message.","Add retry/backoff only when the cause is a RetriableException; otherwise escalate."],"tags":["kafka","consumer","metadata","unexpected","version-skew","diagnostics"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}