{"record":{"id":"31aeec9864893569","repo":"apache/pulsar","slug":"topic-is-invalid","errorCode":null,"errorMessage":"${topic} is invalid","messagePattern":"(.+?) is invalid","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java","lineNumber":571,"sourceCode":"            final List<String> parts = splitBySlash(topic.substring(index + \"://\".length()), 4);\n            if (parts.size() == 4) {\n                throw new IllegalArgumentException(\n                        \"V1 topic names (with cluster component) are no longer supported. \"\n                        + \"Please use the V2 format: '<domain>://tenant/namespace/topic'. Got: \" + topic);\n            }\n            if (parts.size() != 3) {\n                throw new IllegalArgumentException(topic + \" is invalid. \"\n                    + \"Expected format: '<domain>://tenant/namespace/topic'\");\n            }\n            NamespaceName.validateNamespaceName(parts.get(0), parts.get(1));\n            if (StringUtils.isBlank(parts.get(2))) {\n                throw new IllegalArgumentException(topic + \" has blank local topic\");\n            }\n            return topic; // it's a valid full topic name\n        } else {\n            List<String> parts = splitBySlash(topic, 0);\n            if (parts.size() != 1 && parts.size() != 3) {\n                throw new IllegalArgumentException(topic + \" is invalid\");\n            }\n            if (parts.size() == 1) {\n                if (StringUtils.isBlank(parts.get(0))) {\n                    throw new IllegalArgumentException(topic + \" has blank local topic\");\n                }\n                return \"persistent://public/default/\" + parts.get(0);\n            } else {\n                NamespaceName.validateNamespaceName(parts.get(0), parts.get(1));\n                if (StringUtils.isBlank(parts.get(2))) {\n                    throw new IllegalArgumentException(topic + \" has blank local topic\");\n                }\n                return \"persistent://\" + topic;\n            }\n        }\n    }\n\n    private static List<String> splitBySlash(String topic, int limit) {\n        final List<String> tokens = new ArrayList<>(3);","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java#L553-L589","documentation":"When toFullTopicName receives a string without '://', it treats it as a relative/short name and splits it by '/'. If the split yields a number of segments other than 1 (a bare short name) or 3 (tenant/namespace/topic), the method throws this IllegalArgumentException — the relative form is neither a short name nor a full tenant/ns/topic triple.","triggerScenarios":"Calling toFullTopicName() with names like 'my-tenant/my-topic' (2 segments) or 'a/b/c/d' (4+ segments) that contain no '://' scheme.","commonSituations":"Hand-built topic strings with partial paths; passing a namespace-only or tenant-only path; copy-paste of a path fragment from a URL without the domain prefix; confusion between the 1-segment and 3-segment shortcut forms.","solutions":["Use either a bare topic name ('my-topic') or the complete triple ('tenant/namespace/topic') without the domain scheme, or a full URL with '://'","Fix the number of path segments in the input","Prefer the fully qualified 'persistent://tenant/ns/topic' form to avoid ambiguity"],"exampleFix":"// before\nTopicName.toFullTopicName(\"my-tenant/my-topic\");\n// after\nTopicName.toFullTopicName(\"my-tenant/my-ns/my-topic\");","handlingStrategy":"validation","validationCode":"public static boolean isShortOrTripleName(String s) {\n    if (s == null || s.contains(\"://\")) return false;\n    int n = s.split(\"/\").length;\n    return n == 1 || n == 3;\n}","typeGuard":null,"tryCatchPattern":"try {\n    String full = TopicName.toFullTopicName(raw);\n} catch (IllegalArgumentException e) {\n    log.error(\"'{}' is invalid: use a bare topic name or 'tenant/namespace/topic'\", raw);\n}","preventionTips":["Only use the documented relative forms: 'topic' or 'tenant/ns/topic'","Prefer full URLs (with '://') to remove ambiguity","Don't pass tenant-only or namespace-only paths as topic names"],"tags":["java","topic-naming","format-validation"],"backgroundTag":"invalid-topic-name","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"}