apache/pulsar · error · IOException

Invalid privateKey format

Error message

Invalid privateKey format

What it means

loadPrivateKey() wraps URISyntaxException, InstantiationException and IllegalAccessException into IOException('Invalid privateKey format'). This means the privateKey value could not be interpreted as a valid URL at all — typically a malformed URI syntax in the privateKey parameter (not the JSON payload itself, which is handled elsewhere).

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java:146

            URLConnection urlConnection = new org.apache.pulsar.client.api.url.URL(privateKeyURL).openConnection();
            try {
                String protocol = urlConnection.getURL().getProtocol();
                String contentType = urlConnection.getContentType();
                if ("data".equals(protocol) && !"application/json".equals(contentType)) {
                    throw new IllegalArgumentException(
                            "Unsupported media type or encoding format: " + urlConnection.getContentType());
                }
                KeyFile privateKey;
                try (Reader r = new InputStreamReader((InputStream) urlConnection.getContent(),
                        StandardCharsets.UTF_8)) {
                    privateKey = KeyFile.fromJson(r);
                }
                return privateKey;
            } finally {
                IOUtils.close(urlConnection);
            }
        } catch (URISyntaxException | InstantiationException | IllegalAccessException e) {
            throw new IOException("Invalid privateKey format", e);
        }
    }

    @Override
    public void initialize() throws PulsarClientException {
        super.initialize();
        assert this.metadata != null;

        URL tokenUrl = this.metadata.getTokenEndpoint();
        this.exchanger = new TokenClient(tokenUrl, getHttpClient());
        initialized = true;
    }

    public TokenResult authenticate() throws PulsarClientException {
        // read the private key from storage
        KeyFile keyFile;
        try {
            keyFile = loadPrivateKey(this.privateKey);

View on GitHub (pinned to 820761864e)

Solutions

  1. URL-encode special characters in the privateKey value (spaces as %20)
  2. Prefix local paths with file: and ensure valid URI syntax
  3. Log/print the privateKey value (careful with secrets) and test it with new URI(value) first

Example fix

// before
String key = "/etc/pulsar/oauth2/my key.json";
// after
String key = "file:/etc/pulsar/oauth2/my%20key.json";
Defensive patterns

Strategy: validation

Validate before calling

String key = authParams.get("privateKey");
try {
    new java.net.URI(key);
} catch (java.net.URISyntaxException e) {
    throw new IllegalArgumentException("privateKey is not a valid URI: " + e.getMessage());
}

Type guard

boolean isValidKeyUri(String v) {
    if (v == null || v.isBlank()) return false;
    try { new java.net.URI(v); return true; } catch (java.net.URISyntaxException e) { return false; }
}

Try / catch

try {
    flow.initialize();
} catch (PulsarClientException.AuthenticationException e) {
    if (e.getMessage().contains("Invalid privateKey format")) {
        throw new ConfigException("privateKey must be a well-formed URI (URL-encode spaces/special chars)", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: privateKey string containing spaces, unencoded special characters, or an invalid scheme so new URL(privateKeyURL) throws URISyntaxException; file paths with illegal characters; a value like 'file:/path with spaces/key.json'.

Common situations: Paste errors adding whitespace/newlines to the privateKey config; paths with non-URL-safe characters; using a plain path string instead of a proper file: URL.

Related errors


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