{"record":{"id":"1ee3fb7488c895eb","repo":"apache/pulsar","slug":"tlspolicy-purpose-and-policy-must-not-be-null","errorCode":null,"errorMessage":"tlsPolicy purpose and policy must not be null","messagePattern":"tlsPolicy purpose and policy must not be null","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/PulsarClientBuilderV5.java","lineNumber":402,"sourceCode":"        return this;\n    }\n\n    @Override\n    public PulsarClientBuilder transactionPolicy(TransactionPolicy policy) {\n        conf.setEnableTransaction(true);\n        this.transactionTimeout = policy.timeout();\n        return this;\n    }\n\n    @Override\n    public PulsarClientBuilder tlsPolicy(TlsPolicy policy) {\n        return tlsPolicy(TlsPurpose.CLIENT_DEFAULT, policy);\n    }\n\n    @Override\n    public PulsarClientBuilder tlsPolicy(TlsPurpose purpose, TlsPolicy policy) {\n        if (purpose == null || policy == null) {\n            throw new IllegalArgumentException(\"tlsPolicy purpose and policy must not be null\");\n        }\n        // useTls governs the BINARY BROKER TRANSPORT only, so a policy for a different trust domain must not\n        // turn it on. Configuring CLIENT_OAUTH2 (the identity provider) against a plaintext pulsar:// broker\n        // is a legitimate combination — it was enabling TLS toward the broker and failing the connection.\n        // The policy map itself is what triggers TLS-factory creation, so a non-transport purpose still gets\n        // its factory without touching the transport.\n        //\n        // CLIENT_DEFAULT alone, not every client-role purpose: pip-478.md calls this \"one narrow addition\",\n        // being the only v5 expression of the legacy client.conf useTls=true with a plain pulsar:// URL.\n        // BROKER_CLIENT and plugin-minted purposes (TlsPurpose.client(\"...\")) are client-role too, and\n        // enabling the transport for them is the same defect this guard was added to fix.\n        if (TlsPurpose.CLIENT_DEFAULT.equals(purpose)) {\n            conf.setUseTls(true);\n        }\n        Map<TlsPurpose, TlsPolicy> map = conf.getTlsPolicyMap();\n        if (map == null) {\n            map = new LinkedHashMap<>();\n            conf.setTlsPolicyMap(map);","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/PulsarClientBuilderV5.java#L384-L420","documentation":"tlsPolicy(purpose, policy) validates its arguments and throws IllegalArgumentException when either the TlsPurpose or the TlsPolicy is null. The overload tlsPolicy(TlsPolicy) forwards TlsPurpose.CLIENT_DEFAULT, so this error from that path means the policy itself was null. It is a fail-fast guard instead of a NullPointerException deep inside map handling.","triggerScenarios":"Calling clientBuilder.tlsPolicy(null) or clientBuilder.tlsPolicy(purpose, null), or tlsPolicy(somePurpose, policy) where somePurpose is null; typically the result of a variable that failed to initialize or a configuration lookup that returned null.","commonSituations":"Loading TlsPolicy from config/properties where a missing key yields null; a factory method returning null on invalid input; refactoring code where the purpose enum constant was removed or renamed.","solutions":["Pass a real TlsPolicy built via TlsPolicy.builder()...build().","Check the source variable for null before calling tlsPolicy and skip or default the TLS configuration when absent.","If only the purpose may vary, ensure you pass a valid TlsPurpose constant (e.g. TlsPurpose.CLIENT_DEFAULT) or a purpose from TlsPurpose.client(name)."],"exampleFix":"// before\nTlsPolicy policy = loadFromConfig(); // may be null\nbuilder.tlsPolicy(TlsPurpose.CLIENT_DEFAULT, policy); // IllegalArgumentException if null\n// after\nTlsPolicy policy = loadFromConfig();\nif (policy != null) {\n    builder.tlsPolicy(TlsPurpose.CLIENT_DEFAULT, policy);\n}","handlingStrategy":"validation","validationCode":"if (purpose != null && policy != null) {\n    builder.tlsPolicy(purpose, policy);\n}","typeGuard":"static boolean isConfigurableTls(TlsPurpose p, TlsPolicy t) { return p != null && t != null; }","tryCatchPattern":null,"preventionTips":["Build TlsPolicy through TlsPolicy.builder()...build() which itself fails fast on invalid combos.","Never return null from a config-loading helper for TLS; return Optional<TlsPolicy> and skip configuration when empty.","Use the enum constants directly (TlsPurpose.CLIENT_DEFAULT) instead of nullable lookups."],"tags":["pulsar","tls","null-check","illegal-argument","builder"],"backgroundTag":"null-argument-validation","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"}