apache/hadoop · error · AuthenticationException
Invalid SPNEGO sequence, 'WWW-Authenticate' header incorrect
Error message
Invalid SPNEGO sequence, 'WWW-Authenticate' header incorrect: {} What it means
During SPNEGO, KerberosAuthenticator.readToken expects the server's 200/401 response to carry a 'WWW-Authenticate: Negotiate ...' header containing the GSS continuation token. If the header is missing entirely or does not start with 'Negotiate', the handshake cannot proceed and AuthenticationException('Invalid SPNEGO sequence, ... header incorrect: ...') is thrown, including the offending/absent header value. Root cause is almost always that the endpoint is not actually doing Kerberos at the HTTP layer.
Source
Thrown at hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java:396
String token = base64.encodeToString(outToken);
conn.setRequestMethod(AUTH_HTTP_METHOD);
conn.setRequestProperty(AUTHORIZATION, NEGOTIATE + " " + token);
conn.connect();
}
/*
* Retrieves the Kerberos token returned by the server.
*/
private byte[] readToken(HttpURLConnection conn)
throws IOException, AuthenticationException {
int status = conn.getResponseCode();
if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_UNAUTHORIZED) {
String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);
if (authHeader == null) {
authHeader = conn.getHeaderField(WWW_AUTHENTICATE.toLowerCase());
}
if (authHeader == null || !authHeader.trim().startsWith(NEGOTIATE)) {
throw new AuthenticationException("Invalid SPNEGO sequence, '" + WWW_AUTHENTICATE +
"' header incorrect: " + authHeader);
}
String negotiation = authHeader.trim().substring((NEGOTIATE + " ").length()).trim();
return base64.decode(negotiation);
}
throw new AuthenticationException("Invalid SPNEGO sequence, status code: " + status);
}
}
View on GitHub (pinned to 2add963021)
Solutions
- Confirm the server side really offers Kerberos: curl -v --negotiate -u : http://host:port/ must show 'WWW-Authenticate: Negotiate' in the 401 challenge.
- Set the service's authentication.type to kerberos (hadoop-auth filter config) and restart, so challenges are emitted.
- Fix the reverse proxy to pass WWW-Authenticate through (nginx: proxy_pass_header WWW-Authenticate; Apache: appropriate Header directives) or bypass it for testing.
- Verify you hit the intended endpoint/port, not a redirect-to-login or default page.
- If a 200-no-header case persists, disable anonymous auth on the server so it always issues the challenge.
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: server must offer Negotiate
HttpURLConnection probe = (HttpURLConnection) url.openConnection();
int rc = probe.getResponseCode();
String challenge = probe.getHeaderField("WWW-Authenticate");
boolean spnegoReady = (rc == 401 || rc == 200) && challenge != null && challenge.startsWith("Negotiate"); Try / catch
try {
new KerberosAuthenticator().authenticate(url, token);
} catch (AuthenticationException e) {
if (e.getMessage().contains("header incorrect")) {
// endpoint not SPNEGO-enabled or proxy stripped the challenge: fix server/proxy config
throw new IllegalStateException("Server does not offer SPNEGO at " + url, e);
}
throw e;
} Prevention
- Verify with curl -v --negotiate -u : <url> before blaming the client.
- Configure reverse proxies to pass WWW-Authenticate headers untouched.
- Keep server authentication.type=kerberos wherever KerberosAuthenticator clients connect.
When it happens
Trigger: Server configured with authentication.type=simple/pseudo (or anonymous allowed) so the 200 response carries no WWW-Authenticate header; a reverse proxy strips or rewrites WWW-Authenticate; the URL hits a static/error page instead of the SPNEGO-protected endpoint; server is a non-Kerberos service (e.g. a form-login app) returning 200 HTML.
Common situations: Client uses KerberosAuthenticator against a service whose hadoop-auth filter is 'simple'; httpfs/NameNode UI behind Apache/nginx that does not forward the Negotiate challenge; DNS alias vs. SPN mismatch causing the server to skip Negotiate; firewalls/injected proxies replacing 401 challenges with an HTML login page (200).
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid SPNEGO sequence, status code: {}
- Security enabled but user not authenticated by filter
- Failed to obtain user group information: {}
- tokenStr cannot be null
- url cannot be NULL
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/d27ba4957fc8043f.
Report an issue: GitHub.