{"record":{"id":"e1566d66e79912ec","repo":"apache/pulsar","slug":"getpublickey-called-on-a-consumer-side-cryptokeyre","errorCode":null,"errorMessage":"getPublicKey called on a consumer-side CryptoKeyReaderAdapter","messagePattern":"getPublicKey called on a consumer-side CryptoKeyReaderAdapter","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/CryptoKeyReaderAdapter.java","lineNumber":67,"sourceCode":"\n    /**\n     * Producer-side adapter: only {@link CryptoKeyReader#getPublicKey} is supported.\n     */\n    static CryptoKeyReader forProducer(PublicKeyProvider provider) {\n        return new CryptoKeyReaderAdapter(provider, null);\n    }\n\n    /**\n     * Consumer-side adapter: only {@link CryptoKeyReader#getPrivateKey} is supported.\n     */\n    static CryptoKeyReader forConsumer(PrivateKeyProvider provider) {\n        return new CryptoKeyReaderAdapter(null, provider);\n    }\n\n    @Override\n    public EncryptionKeyInfo getPublicKey(String keyName, Map<String, String> metadata) {\n        if (publicKeyProvider == null) {\n            throw new UnsupportedOperationException(\n                    \"getPublicKey called on a consumer-side CryptoKeyReaderAdapter\");\n        }\n        var v5Key = publicKeyProvider.getPublicKey(keyName).join();\n        return new EncryptionKeyInfo(v5Key.key(), v5Key.metadata());\n    }\n\n    @Override\n    public EncryptionKeyInfo getPrivateKey(String keyName, Map<String, String> metadata) {\n        if (privateKeyProvider == null) {\n            throw new UnsupportedOperationException(\n                    \"getPrivateKey called on a producer-side CryptoKeyReaderAdapter\");\n        }\n        var v5Key = privateKeyProvider.getPrivateKey(keyName, metadata).join();\n        return new EncryptionKeyInfo(v5Key.key(), v5Key.metadata());\n    }\n}\n","sourceCodeStart":49,"sourceCodeEnd":84,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/CryptoKeyReaderAdapter.java#L49-L84","documentation":"CryptoKeyReaderAdapter wraps a v5 key provider for the legacy CryptoKeyReader interface. An adapter built only with a publicKeyProvider is producer-side; calling getPublicKey on a consumer-side adapter (built with only a privateKeyProvider) throws UnsupportedOperationException because there is no public key provider to delegate to.","triggerScenarios":"Configuring a producer's encryption with an adapter created from a consumer-side key provider (privateKeyProvider == null), then the producer (or client code) invokes getPublicKey.","commonSituations":"Copy-pasting consumer crypto configuration into a producer; sharing one adapter instance between a producer and consumer; a library defaulting to the consumer-side factory method CryptoKeyReaderAdapter.forConsumer(...) in producer setup.","solutions":["Build the adapter with the producer-side factory / a non-null publicKeyProvider before using it for message encryption.","Use separate adapter instances for producer (public keys) and consumer (private keys).","Check the factory method used — forConsumer vs forProducer — matches the client role."],"exampleFix":"// before\nCryptoKeyReader reader = CryptoKeyReaderAdapter.forConsumer(privateKeyProvider);\nProducer<byte[]> p = client.newProducer().cryptoKeyReader(reader); // producer needs public keys\n// after\nCryptoKeyReader reader = CryptoKeyReaderAdapter.forProducer(publicKeyProvider);\nProducer<byte[]> p = client.newProducer().cryptoKeyReader(reader);","handlingStrategy":"type-guard","validationCode":"// Ensure the adapter was built for producers before wiring it into a Producer\nCryptoKeyReaderAdapter adapter = CryptoKeyReaderAdapter.forProducer(publicKeyProvider);\nproducerBuilder.cryptoKeyReader(adapter);","typeGuard":"static boolean supportsPublicKeys(CryptoKeyReaderAdapter a) {\n    return a != null && a.isProducerSide(); // or track the factory used at construction\n}","tryCatchPattern":"try {\n    EncryptionKeyInfo ki = adapter.getPublicKey(keyName, metadata);\n} catch (UnsupportedOperationException e) {\n    throw new IllegalStateException(\"Producer configured with consumer-side key reader\", e);\n}","preventionTips":["Always use the role-specific factory (forProducer / forConsumer).","Never share one CryptoKeyReaderAdapter between producer and consumer.","Add a startup assertion that producer crypto config includes a public key provider."],"tags":["encryption","crypto","unsupported-operation"],"backgroundTag":"wrong-crypto-key-reader-role","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"}