{"id":"b79ff38411bd7e47","repo":"apache/kafka","slug":"topic-topic-is-invalid","errorCode":null,"errorMessage":"Topic '${topic}' is invalid","messagePattern":"Topic '(.+?)' is invalid","errorType":"exception","errorClass":"InvalidTopicException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/TopicMetadataFetcher.java","lineNumber":128,"sourceCode":"\n                Set<String> unauthorizedTopics = cluster.unauthorizedTopics();\n                if (!unauthorizedTopics.isEmpty())\n                    throw new TopicAuthorizationException(unauthorizedTopics);\n\n                boolean shouldRetry = false;\n                Map<String, Errors> errors = response.errors();\n                if (!errors.isEmpty()) {\n                    // 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                }","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/TopicMetadataFetcher.java#L110-L146","documentation":"Thrown as InvalidTopicException by TopicMetadataFetcher.getTopicMetadata when the broker's MetadataResponse carries Errors.INVALID_TOPIC_EXCEPTION for at least one requested topic. INVALID_TOPIC_EXCEPTION on the broker side means the topic name failed server-side validation (illegal characters, length, or '.' / '_' conflicts), distinct from UNKNOWN_TOPIC_OR_PARTITION which is silently skipped. The client surfaces it as a hard, non-retriable failure.","triggerScenarios":"Calling consumer.partitionsFor(topic) / listTopics() / subscribe() with a topic name containing illegal characters (must match [a-zA-Z0-9._-], max 249 chars), or a name equal to '.' or '..'. Also triggered when a topic name conflicts with an internal one.","commonSituations":"Topic names with forward slash '/', comma, or colon from templated config; names longer than 249 chars from dynamic naming; topic auto-created by another client with a typo (e.g. 'orders/eur'); using a fully-qualified 'namespace.topic' style where the namespace has illegal characters.","solutions":["Sanitize the topic name to match ^[a-zA-Z0-9\\._-]{1,249}$ and avoid '.' or '..' exactly.","If the topic was meant to exist, verify it via kafka-topics --describe; recreate with a valid name if it was auto-created with a bad name.","Patch the producer of the bad topic name (config templating, env-var interpolation) so future runs don't recreate it.","Disable auto.create.topics.enable on the broker if stray names are getting auto-created."],"exampleFix":"// before\nconsumer.partitionsFor(\"orders/eur\"); // '/' is illegal\n\n// after\nString topic = \"orders.eur\"; // legal charset\nconsumer.partitionsFor(topic);","handlingStrategy":"validation","validationCode":"// Validate topic name against Kafka naming rules before subscribe/partitionFor.\nstatic final java.util.regex.Pattern NAME = java.util.regex.Pattern.compile(\"^[a-zA-Z0-9._-]+$\");\nstatic boolean isValidTopicName(String t) {\n    return t != null && t.length() >= 1 && t.length() <= 249\n        && !t.equals(\".\") && !t.equals(\"..\")\n        && NAME.matcher(t).matches();\n}\nif (!isValidTopicName(topic)) throw new IllegalArgumentException(\"bad topic name: \" + topic);","typeGuard":"import java.util.regex.Pattern;\n\n/** Narrows a String to a Kafka-valid topic name (length 1-249, [A-Za-z0-9._-], not '.' / '..'). */\nstatic boolean isValidTopicName(String topic) {\n    if (topic == null || topic.isEmpty() || topic.length() > 249) return false;\n    if (topic.equals(\".\") || topic.equals(\"..\")) return false;\n    for (int i = 0; i < topic.length(); i++) {\n        char c = topic.charAt(i);\n        boolean ok = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')\n            || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-';\n        if (!ok) return false;\n    }\n    return true;\n}","tryCatchPattern":"try {\n    consumer.partitionsFor(topic);\n} catch (org.apache.kafka.common.errors.InvalidTopicException e) {\n    log.warn(\"Rejected invalid topic name '{}'; fix config/source, do not retry as-is\", topic);\n    throw e; // not retriable — the name will not become valid on its own\n}","preventionTips":["Validate topic names at config/source ingestion time, not at the Kafka call site.","Wrap topic creation in a factory that enforces the naming regex and length cap (249).","Reject '.' and '..' and names with '/' or control characters explicitly.","Add a unit test over your topic-name source so invalid names never reach the client."],"tags":["kafka","consumer","topic-name","validation","metadata"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}