{"record":{"id":"94eae28d6f1d8997","repo":"apache/pulsar","slug":"invalid-topic-name-completetopicname-94eae2","errorCode":null,"errorMessage":"Invalid topic name: ${completeTopicName}","messagePattern":"Invalid topic name: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java","lineNumber":241,"sourceCode":"                }\n\n                if (this.domain == TopicDomain.segment) {\n                    this.completeTopicName = String.format(\"%s://%s/%s/%s/%s\",\n                            domain, tenant, namespacePortion, localName,\n                            String.format(\"%04x-%04x-%d\", segmentRange.start(), segmentRange.end(), segmentId));\n                } else {\n                    this.completeTopicName = completeTopicName;\n                }\n            }\n\n            if (StringUtils.isBlank(localName)) {\n                throw new IllegalArgumentException(String.format(\"Invalid topic name: %s. Topic local name must not\"\n                        + \" be blank.\", completeTopicName));\n            }\n            this.partitionIndex = getPartitionIndex(localName);\n            this.namespaceName = NamespaceName.get(tenant, namespacePortion);\n        } catch (NullPointerException e) {\n            throw new IllegalArgumentException(\"Invalid topic name: \" + completeTopicName, e);\n        }\n    }\n\n    public boolean isPersistent() {\n        return TopicDomain.persistent == domain || TopicDomain.topic == domain || TopicDomain.segment == domain;\n    }\n\n    public boolean isScalable() {\n        return TopicDomain.topic == domain;\n    }\n\n    public boolean isSegment() {\n        return TopicDomain.segment == domain;\n    }\n\n    /**\n     * Get the segment hash range for segment:// topics.\n     *","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java#L223-L259","documentation":"When parsing the topic name throws a NullPointerException internally (e.g. a null or badly-structured input where an expected segment is absent), TopicName's constructor catches the NPE and rethrows it as an IllegalArgumentException with the message 'Invalid topic name: <input>', preserving the NPE as the cause. It exists so callers get a consistent, meaningful validation error instead of a raw NPE.","triggerScenarios":"Calling TopicName.get() / new TopicName(...) with a null or malformed string that causes a NullPointerException during parsing — e.g. null input, or a name that fails the expected 'domain://tenant/namespace/local' structure so an expected part is missing.","commonSituations":"Passing an unvalidated config value or method argument that is null; a topic name with too few segments causing an array/list index to be missing; test fixtures with placeholder nulls; deserialization producing null topic fields.","solutions":["Log/inspect the exception cause (getCause()) to see the underlying NPE and which segment was missing","Ensure the input is non-null and follows '<domain>://<tenant>/<namespace>/<local-name>'","Add an explicit null/format check in your code before calling TopicName.get()"],"exampleFix":"// before\nTopicName.get(config.getTopic()); // getTopic() may return null\n// after\nString t = config.getTopic();\nif (t == null || !t.contains(\"://\")) { throw new ConfigException(\"topic must be a full topic URL\"); }\nTopicName.get(t);","handlingStrategy":"validation","validationCode":"public static void requireNotNullTopic(String topic) {\n    java.util.Objects.requireNonNull(topic, \"topic name must not be null\");\n    if (!topic.contains(\"://\")) throw new IllegalArgumentException(\"topic must be a full topic URL: \" + topic);\n}","typeGuard":"public static boolean isNonNullFullTopic(String s) { return s != null && s.contains(\"://\"); }","tryCatchPattern":"try {\n    TopicName tn = TopicName.get(input);\n} catch (IllegalArgumentException e) {\n    Throwable cause = e.getCause(); // NPE shows which parse step failed\n    log.error(\"Invalid topic '{}': {}\", input, cause == null ? e.getMessage() : cause.toString());\n}","preventionTips":["Null-check topic strings before calling TopicName.get","Use Objects.requireNonNull with a helpful message at API boundaries","Inspect getCause() when you see 'Invalid topic name' with no format detail — an NPE cause means a structurally broken name","Keep test fixtures using real topic names, not nulls"],"tags":["java","topic-naming","null-pointer"],"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-14T05:17:10.506Z"}