apache/pulsar · error · IllegalArgumentException

Failed to read decryption key from ${keyUri}

Error message

Failed to read decryption key from ${keyUri}

What it means

buildFileDecryptionPolicy reads the decryption key file named by keyUri with Files.readAllBytes and wraps any IOException into an IllegalArgumentException. It means the file:// key location was valid as a URI but the bytes could not be read — typically the file is missing, unreadable, or a directory.

Source

Thrown at pulsar-client-tools/src/main/java/org/apache/pulsar/client/cli/AbstractCmdConsume.java:211

            }
            res.put(f.name(), fieldValue);
        }
        return res;
    }

    /**
     * Build a consumer-side decryption policy from a {@code file://} key URI, mirroring the v4
     * {@code defaultCryptoKeyReader(uri)} semantics: the private key is loaded once and returned
     * for any key name. (The producer's logical key name travels in the message metadata, so a
     * name-keyed provider would not resolve it; the CLI's file-based flow has a single key.)
     */
    protected static ConsumerEncryptionPolicy buildFileDecryptionPolicy(
            String keyUri, ConsumerCryptoFailureAction failureAction) {
        final byte[] keyBytes;
        try {
            keyBytes = Files.readAllBytes(fileUriToPath(keyUri));
        } catch (IOException e) {
            throw new IllegalArgumentException("Failed to read decryption key from " + keyUri, e);
        }
        PrivateKeyProvider provider = (keyName, metadata) ->
                CompletableFuture.completedFuture(EncryptionKey.of(keyBytes));
        return ConsumerEncryptionPolicy.builder()
                .privateKeyProvider(provider)
                .failureAction(failureAction)
                .build();
    }

    @WebSocket
    @CustomLog
    public static class ConsumerSocket {
        private static final String X_PULSAR_MESSAGE_ID = "messageId";
        private final CountDownLatch closeLatch;
        private Session session;
        private CompletableFuture<Void> connected;
        final BlockingQueue<String> incomingMessages;

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the resolved path exists and is a regular file (Files.isRegularFile) and is readable (Files.isReadable)
  2. Fix the file:// URI (absolute path, correct host-empty form file:///path)
  3. Check filesystem permissions/ownership for the user running pulsar-client, and that any volume mount is present
  4. If the key is provisioned at startup, add a readiness check or wait loop before launching the consumer

Example fix

// before
--decryption-key file:///etc/pulsar/decrytion-key.pem   // typo, file absent
// after
ls -l /etc/pulsar/decryption-key.pem   # verify first
--decryption-key file:///etc/pulsar/decryption-key.pem
Defensive patterns

Strategy: validation

Validate before calling

Path p = fileUriToPath(keyUri);
if (!Files.isRegularFile(p) || !Files.isReadable(p))
    throw new IllegalArgumentException("Decryption key not readable: " + p);

Try / catch

try {
    ConsumerEncryptionPolicy pol = buildFileDecryptionPolicy(keyUri, action);
} catch (IllegalArgumentException e) {
    Throwable cause = e.getCause();
    if (cause instanceof NoSuchFileException) {
        LOG.error("Key file missing: {}", ((NoSuchFileException) cause).getFile());
    } else if (cause instanceof AccessDeniedException) {
        LOG.error("Key file not readable by current user");
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling CmdConsume with a decryption key URI whose path does not exist, lacks read permission, is a directory, or whose device/path vanished (container mount not present, NFS down).

Common situations: Kubernetes/pod volume not mounted where the key was expected; typo in the key filename; file created by root but CLI runs as another user; relative path resolved against an unexpected working directory.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/a87c248f98cdac6d. Report an issue: GitHub.