{"record":{"id":"abc988635e6112ed","repo":"apache/pulsar","slug":"invalid-namespace-format-expected-tenant-names","errorCode":null,"errorMessage":"Invalid namespace format. expected <tenant>/<namespace> but got: ${namespace}","messagePattern":"Invalid namespace format\\. expected <tenant>/<namespace> but got: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/naming/NamespaceName.java","lineNumber":107,"sourceCode":"        // Verify it's a proper namespace\n        // The namespace name is composed of <tenant>/<namespace>\n        try {\n\n            String[] parts = namespace.split(\"/\");\n            if (parts.length == 2) {\n                validateNamespaceName(parts[0], parts[1]);\n\n                tenant = parts[0];\n                localName = parts[1];\n            } else if (parts.length == 3) {\n                throw new IllegalArgumentException(\n                    \"V1 namespace names (with cluster component) are no longer supported. \"\n                    + \"Please use the V2 format: '<tenant>/<namespace>'. Got: \" + namespace);\n            } else {\n                throw new IllegalArgumentException(\"Invalid namespace format. namespace: \" + namespace);\n            }\n        } catch (IllegalArgumentException | NullPointerException e) {\n            throw new IllegalArgumentException(\"Invalid namespace format.\"\n                    + \" expected <tenant>/<namespace>\"\n                    + \" but got: \" + namespace, e);\n        }\n        this.namespace = namespace;\n    }\n\n    public String getTenant() {\n        return tenant;\n    }\n\n    public String getLocalName() {\n        return localName;\n    }\n\n    public String getPersistentTopicName(String localTopic) {\n        return getTopicName(TopicDomain.persistent, localTopic);\n    }\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/naming/NamespaceName.java#L89-L125","documentation":"This is the outer wrapper thrown by the NamespaceName constructor's catch block: any IllegalArgumentException (including the V1-unsupported and bad-format messages) or NullPointerException raised while parsing is rethrown with the message 'Invalid namespace format. expected <tenant>/<namespace> but got: <input>'. It tells the developer the library expects exactly '<tenant>/<namespace>'.","triggerScenarios":"NamespaceName.get(...) with a null input (NPE at namespace.split), a V1 three-part name 'tenant/cluster/namespace' (the inner V1-not-supported IAE), an invalid tenant/localName rejected by NamedEntity.checkName, or 1/4+ segment names.","commonSituations":"Upgrading code that still uses V1 namespace names with a cluster component; empty tenant or namespace segments like 'tenant/' or '/default'; illegal characters in tenant or namespace names; null namespace strings from unset configuration.","solutions":["Inspect the 'but got:' portion of the message and correct the input to the '<tenant>/<namespace>' form.","If the input is a V1 name (three segments), remove the cluster segment: 'tenant/cluster/ns' -> 'tenant/ns'.","If the input is null, fix the configuration or caller so a real namespace string is supplied.","If tenant or namespace segments are empty or contain illegal characters, rename them to valid non-empty identifiers.","Pre-validate with NamespaceName.validateNamespaceName(tenant, namespace) or NamespaceName.isValid(String) before calling get()."],"exampleFix":"// before\nNamespaceName ns = NamespaceName.get(\"my-tenant/us-west/my-ns\"); // V1\n// after\nNamespaceName ns = NamespaceName.get(\"my-tenant/my-ns\"); // V2","handlingStrategy":"try-catch","validationCode":"if (ns != null && ns.matches(\"[^/]+/[^/]+\")) {\n    NamespaceName n = NamespaceName.get(ns);\n}","typeGuard":"static Optional<NamespaceName> tryParseNamespace(String ns) {\n    try {\n        return Optional.of(NamespaceName.get(ns));\n    } catch (IllegalArgumentException e) {\n        return Optional.empty();\n    }\n}","tryCatchPattern":"try {\n    NamespaceName ns = NamespaceName.get(raw);\n} catch (IllegalArgumentException e) {\n    // message includes 'but got: <input>' plus cause (V1 name, bad chars, null)\n    throw new ConfigurationException(\"Namespace must be '<tenant>/<namespace>' (V2). Cause: \" + e.getMessage(), e);\n}","preventionTips":["Migrate any remaining V1 'tenant/cluster/namespace' strings to V2 'tenant/namespace'.","Check the exception cause (getCause()) to distinguish V1-format from character-validation failures.","Centralize namespace parsing in one utility that logs and wraps this error consistently."],"tags":["pulsar","namespace","illegal-argument","migration"],"backgroundTag":"invalid-namespace-format","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"}