apache/pulsar · error · PulsarClientException.UnsupportedAuthenticationException
v4 plugin ${v4.getClass().getName} provided no HTTP auth hea
Error message
v4 plugin ${v4.getClass().getName} provided no HTTP auth headers (hasDataForHttp()/getHttpHeaders() returned nothing) What it means
For HTTP-based v5 authentication, the v4 adapter asks the legacy plugin for HTTP headers via getAuthData() -> hasDataForHttp()/getHttpHeaders(). If the provider is null, reports no HTTP data, or returns null headers, getHttpHeadersAsync throws UnsupportedAuthenticationException naming the plugin, since the v5 HTTP flow cannot proceed without auth headers.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/v5/LegacyV4AuthenticationAdapter.java:407
AuthChallenge challenge) {
return supplyOffloaded(() -> {
AuthenticationDataProvider d = callContext.getStateObject(AuthenticationDataProvider.class)
.orElse(null);
if (d == null) {
d = v4.getAuthData(callContext.brokerHost());
callContext.setStateObject(AuthenticationDataProvider.class, d);
}
AuthData response = d.authenticate(AuthData.of(challenge.bytes()));
return new ChallengeResponse(response == null ? null : response.getBytes());
});
}
@Override
public CompletableFuture<HttpAuthHeaders> getHttpHeadersAsync(HttpAuthCallContext callContext) {
return supplyOffloaded(() -> {
AuthenticationDataProvider d = v4.getAuthData();
if (d == null || !d.hasDataForHttp() || d.getHttpHeaders() == null) {
throw new PulsarClientException.UnsupportedAuthenticationException(
"v4 plugin " + v4.getClass().getName() + " provided no HTTP auth headers "
+ "(hasDataForHttp()/getHttpHeaders() returned nothing)");
}
Map<String, String> headers = new HashMap<>();
for (Map.Entry<String, String> e : d.getHttpHeaders()) {
headers.put(e.getKey(), e.getValue());
}
return HttpAuthHeaders.of(headers);
});
}
}
/**
* Adapter for plugins that drive a multi-stage challenge/response flow such as SASL, where the v4
* {@link AuthenticationDataProvider#authenticate(AuthData)} method is used to exchange tokens.
*
* <p>The per-exchange v4 {@link AuthenticationDataProvider} is stored in the call-context state slot
* so the same provider instance handles the whole challenge/response exchange.View on GitHub (pinned to 820761864e)
Solutions
- Use a v4 plugin that implements hasDataForHttp()/getHttpHeaders(), or switch to a v5-native HTTP-capable authentication plugin.
- If you own the plugin, implement hasDataForHttp() returning true and populate getHttpHeaders() with the required auth headers.
- Configure separate authentication for the HTTP path if the binary-protocol plugin cannot produce HTTP headers.
- Check the plugin's configuration so it recognizes the request and produces header data (some plugins gate on endpoint).
Example fix
// before (in v4 plugin)
public boolean hasDataForHttp() { return false; }
// after
@Override
public boolean hasDataForHttp() { return true; }
@Override
public List<KeyValuePair> getHttpHeaders() {
return Collections.singletonList(new KeyValuePair("Authorization", "Bearer " + token));
} Defensive patterns
Strategy: validation
Validate before calling
AuthenticationDataProvider d = v4.getAuthData();
boolean httpCapable = d != null && d.hasDataForHttp() && d.getHttpHeaders() != null;
if (!httpCapable) {
throw new IllegalStateException("plugin cannot produce HTTP headers; use an HTTP-capable plugin");
} Type guard
static boolean supportsHttpAuth(org.apache.pulsar.client.api.Authentication a) throws Exception {
AuthenticationDataProvider d = a.getAuthData();
return d != null && d.hasDataForHttp() && d.getHttpHeaders() != null;
} Try / catch
try {
HttpAuthHeaders h = adapter.getHttpHeadersAsync(ctx).join();
} catch (java.util.concurrent.CompletionException e) {
if (e.getCause() instanceof PulsarClientException.UnsupportedAuthenticationException
&& e.getCause().getMessage().contains("provided no HTTP auth headers")) {
// switch to an HTTP-capable auth plugin
} else throw e.getCause();
} Prevention
- Verify hasDataForHttp()/getHttpHeaders() on the plugin before routing HTTP traffic through it.
- Use plugins explicitly documented as supporting HTTP (websocket/REST) auth.
- Keep binary-protocol and HTTP auth configuration separate.
When it happens
Trigger: A wrapped v4 plugin whose AuthenticationDataProvider returns hasDataForHttp()==false or getHttpHeaders()==null during getHttpHeadersAsync — typically a plugin designed only for the binary command/TLS flow, not HTTP.
Common situations: Using a v4 token/cert plugin meant for the Pulsar binary protocol against an HTTP endpoint (e.g. websocket or admin REST auth path); plugin implementations that only populate HTTP headers when a specific context is present.
Related errors
- v4 plugin ${v4.getClass().getName} returned no Authenticatio
- authentication plugin does not expose BinaryAuthDataProvide
- Invalid broker configuration. Authentication must be enabled
- Invalid combination of Original principal cannot be empty if
- Need to authenticate to perform the request
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/3834d42e79ef0266.
Report an issue: GitHub.