apache/pulsar · error · IllegalArgumentException

Unsupported media type or encoding format: ${contentType}

Error message

Unsupported media type or encoding format: ${contentType}

What it means

ClientCredentialsFlow.loadPrivateKey() opens a URL for the privateKey and, when the protocol is 'data', requires the content type to be application/json. A data: URI with any other content type is rejected with IllegalArgumentException('Unsupported media type or encoding format: ...') because the key file must be JSON (KeyFile.fromJson).

Source

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

                .jcaProvider(jcaProvider)
                .build();
    }

    /**
     * Loads the private key from the given URL.
     *
     * @param privateKeyURL
     * @return
     * @throws IOException
     */
    private static KeyFile loadPrivateKey(String privateKeyURL) throws IOException {
        try {
            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 {

View on GitHub (pinned to 820761864e)

Solutions

  1. Use a data URI with explicit JSON type: data:application/json;base64,<base64 of key json>
  2. Decode the key and pass a file:// or data:application/json URI
  3. Verify the URI encodes ';base64' correctly when the payload is base64

Example fix

// before
String key = "data:text/plain;base64,eyJjbGllbnRJZCI6Ii4uLiJ9";
// after
String key = "data:application/json;base64,eyJjbGllbnRJZCI6Ii4uLi4ifQ==";
Defensive patterns

Strategy: validation

Validate before calling

String key = authParams.get("privateKey");
if (key != null && key.startsWith("data:")) {
    int semi = key.indexOf(';');
    String type = key.substring(5, semi > 0 ? semi : key.length());
    if (!"application/json".equals(type)) {
        throw new IllegalArgumentException("data URI privateKey must be application/json, got: " + type);
    }
}

Type guard

boolean isJsonDataUri(String uri) {
    return uri != null && uri.startsWith("data:application/json")
        && (uri.length() == "data:application/json".length()
            || uri.charAt("data:application/json".length()) == ';' || uri.charAt("data:application/json".length()) == ',');
}

Try / catch

try {
    flow.initialize();
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Unsupported media type")) {
        throw new ConfigException("Fix privateKey data URI to data:application/json;base64,...", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: privateKey supplied as a data: URI whose declared media type is not application/json, e.g. data:text/plain;base64,... or data:;base64,...; the URI encoding drops or alters the content type.

Common situations: Embedding the OAuth2 key JSON as a data URI in config (common in Kubernetes secrets) with the wrong MIME type; hand-encoding the base64 payload and forgetting ';base64' or the type segment.

Related errors


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