{"record":{"id":"ddcff4eac8ffb1f8","repo":"apache/pulsar","slug":"invalid-namespace-format-namespace-namespace","errorCode":null,"errorMessage":"Invalid namespace format. namespace: ${namespace}","messagePattern":"Invalid namespace format\\. namespace: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/naming/NamespaceName.java","lineNumber":104,"sourceCode":"\n    @SuppressFBWarnings(\"DCN_NULLPOINTER_EXCEPTION\")\n    private NamespaceName(String namespace) {\n        // 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) {","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/naming/NamespaceName.java#L86-L122","documentation":"NamespaceName parses names in the V2 form '<tenant>/<namespace>'. This throw fires when the split on '/' yields anything other than 2 or 3 parts (e.g. no slash, or more than two slashes), i.e. the string is not a well-formed namespace name. It is immediately re-wrapped by the catch block with the fuller 'expected <tenant>/<namespace>' message, so callers normally see the wrapped variant.","triggerScenarios":"Calling NamespaceName.get(String) or new via the public factory with a string containing zero '/' (e.g. 'my-tenant') or 4+ segments (e.g. 'a/b/c/d'), or with a null string (NPE caught and rethrown as this path's wrapper).","commonSituations":"Passing a bare topic or tenant name instead of tenant/namespace; reading a namespace from a config property/env var that was never set (yields 'null' or empty); concatenating tenant and namespace with the wrong separator; V1-style names edited incorrectly leaving extra slashes.","solutions":["Format the name as '<tenant>/<namespace>' with exactly one slash, e.g. NamespaceName.get(\"public/default\").","Check the config/env source: if the value is null, empty, or missing the slash, fix the configuration before constructing the NamespaceName.","If you have separate tenant and namespace strings, build with NamespaceName.get(tenant, namespace) instead of string concatenation.","If you hold a legacy V1 name (tenant/cluster/namespace), migrate to the V2 form by dropping the cluster component."],"exampleFix":"// before\nNamespaceName ns = NamespaceName.get(\"my-tenant\");\n// after\nNamespaceName ns = NamespaceName.get(\"my-tenant/my-namespace\");","handlingStrategy":"validation","validationCode":"boolean isValidNamespaceString(String ns) {\n    return ns != null && ns.chars().filter(c -> c == '/').count() == 1\n            && !ns.startsWith(\"/\") && !ns.endsWith(\"/\");\n}\n// use: if (isValidNamespaceString(input)) NamespaceName.get(input);","typeGuard":"static boolean isWellFormedNamespace(String ns) {\n    if (ns == null) return false;\n    String[] parts = ns.split(\"/\", -1);\n    return parts.length == 2 && !parts[0].isEmpty() && !parts[1].isEmpty();\n}","tryCatchPattern":"try {\n    NamespaceName ns = NamespaceName.get(input);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Rejected namespace '{}': {}\", input, e.getMessage());\n    // fail fast or substitute a validated default\n}","preventionTips":["Always build namespaces from separate tenant/namespace variables via NamespaceName.get(tenant, ns) rather than string concatenation.","Validate with NamespaceName.isValid(String) before calling get().","Treat empty/absent config values as errors before they reach name construction."],"tags":["pulsar","namespace","illegal-argument","input-validation"],"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-14T00:17:10.932Z"}