apache/pulsar · error · RestException
Invalid combination of Original principal cannot be empty if
Error message
Invalid combination of Original principal cannot be empty if the request is via proxy.
What it means
When a request arrives through a proxy, the authenticated principal is the proxy role and the real caller is conveyed as the original principal. validateOriginalPrincipal consults AuthorizationService.isValidOriginalPrincipal; if the combination is invalid — e.g. the original principal is empty/blank while the request comes via a proxy role — the admin resource rejects the call with HTTP 401 and this message.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:201
public boolean isRequestHttps() {
return "https".equalsIgnoreCase(httpRequest.getScheme());
}
public String getWebServiceListenerName() {
if (httpRequest == null) {
return null;
}
return (String) httpRequest.getAttribute(WebService.ATTRIBUTE_LISTENER_NAME);
}
public static boolean isClientAuthenticated(String appId) {
return appId != null;
}
private void validateOriginalPrincipal(String authenticatedPrincipal, String originalPrincipal) {
if (!pulsar.getBrokerService().getAuthorizationService()
.isValidOriginalPrincipal(authenticatedPrincipal, originalPrincipal, clientAuthData())) {
throw new RestException(Status.UNAUTHORIZED,
"Invalid combination of Original principal cannot be empty if the request is via proxy.");
}
}
protected boolean hasSuperUserAccess() {
try {
validateSuperUserAccess();
} catch (Exception e) {
return false;
}
return true;
}
public CompletableFuture<Void> validateSuperUserAccessAsync() {
if (!config().isAuthenticationEnabled() || !config().isAuthorizationEnabled()) {
return CompletableFuture.completedFuture(null);
}
String appId = clientAppId();View on GitHub (pinned to 820761864e)
Solutions
- Configure the client/proxy to send the X-Original-Principal header with the real caller role
- Verify the proxy is in broker's proxyRoles so the original-principal logic is applied
- If not using a proxy, connect directly to the broker so no original principal is required
- Check AuthorizationService.isValidOriginalPrincipal logic/implementation for your auth provider
Example fix
// before (proxy-forwarded request) curl -H "Authorization: Bearer <proxy-token>" http://proxy:8080/admin/v2/clusters // after curl -H "Authorization: Bearer <proxy-token>" -H "X-Original-Principal: admin-client" http://proxy:8080/admin/v2/clusters
Defensive patterns
Strategy: validation
Validate before calling
// client-side: ensure original principal is forwarded when going through a proxy
if (usingProxy && (originalPrincipal == null || originalPrincipal.isBlank())) {
throw new IllegalStateException("X-Original-Principal must be set when connecting through a proxy");
} Try / catch
try {
admin.tenants().getTenant(tenant);
} catch (PulsarAdminException e) {
if (e.getStatusCode() == 401) {
// check proxy/original-principal configuration
}
throw e;
} Prevention
- Always set X-Original-Principal when clients connect via a proxy
- Keep the proxy role listed in broker proxyRoles
- Integration-test proxied admin calls in staging
When it happens
Trigger: Calling an admin REST endpoint through a proxy without setting the X-Original-Principal header (or setting it empty); a client behind proxyRoles whose forwarded original principal is blank; misconfigured proxy that strips the original-principal header.
Common situations: Deployments fronting the broker with Pulsar proxy but clients not configured to pass original principal; custom gateways dropping the header; authentication enabled but proxy forwarding not set up.
Related errors
- Proxy not authorized for super-user operation (proxy:%s)
- Original principal not authorized for super-user operation (
- Need to authenticate to perform the request
- Time-out while checking authorization
- Failed to get permissions
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/8a1fd56b6999b2a3.
Report an issue: GitHub.