apache/iceberg · error · NotAuthorizedException
Not authorized
Error message
Not authorized: %s: %s
What it means
The OAuth2 error handler (OAuth2Client's error handler) maps an OAuth token endpoint response with error type 'invalid_client' to NotAuthorizedException. The token server rejected the client credentials — the client ID/secret or token is invalid. Message includes the OAuth error type and description.
Solutions
- Verify the 'credential' property format is exactly 'client-id:client-secret' and both are correct
- Confirm the client credentials are still active with your OAuth2/token issuer (not rotated or revoked)
- If using a static token, verify the token itself is valid and unexpired
- Check the oauth2-server-uri points at the correct token endpoint
Example fix
// before
props.put("credential", "myclient wrongsecret"); // wrong separator/secret
// after
props.put("credential", "myclient:correct-secret"); // client-id:client-secret Defensive patterns
Strategy: validation
Validate before calling
String credential = props.get("credential");
if (credential != null && credential.indexOf(':') <= 0) {
throw new IllegalArgumentException("credential must be 'client-id:client-secret'");
} Try / catch
try {
String token = OAuth2Util.fetchToken(client, authConfig);
} catch (NotAuthorizedException e) {
throw new IllegalStateException("Invalid client credentials: " + e.getMessage(), e);
} Prevention
- Validate credential format client-id:client-secret before building the catalog
- Sync credentials from a secret manager rather than hardcoding
- Test token exchange at startup, not on first catalog call
When it happens
Trigger: Token exchange call to the OAuth2/token endpoint (via OAuth2Util or token fetch in the REST client) returned HTTP 400 with error=invalid_client, meaning client authentication failed.
Common situations: Wrong or rotated client secret in catalog properties, typos in 'credential' (client-id:client-secret), using a revoked client, or sending a client credential where a token is required.
Related errors
- Malformed request
- Not authorized
- Failed to refresh token
- Invalid credential:
- Cannot call commit on temporary table operations
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d428c7ec23be447e.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/rest/ErrorHandlers.java:379
private static class OAuthErrorHandler extends ErrorHandler {
private static final ErrorHandler INSTANCE = new OAuthErrorHandler();
@Override
public ErrorResponse parseResponse(int code, String json) {
try {
return OAuthErrorResponseParser.fromJson(code, json);
} catch (Exception x) {
LOG.warn("Unable to parse error response", x);
}
return ErrorResponse.builder().responseCode(code).withMessage(json).build();
}
@Override
public void accept(ErrorResponse error) {
if (error.type() != null) {
switch (error.type()) {
case OAuth2Properties.INVALID_CLIENT_ERROR:
throw new NotAuthorizedException(
"Not authorized: %s: %s", error.type(), error.message());
case OAuth2Properties.INVALID_REQUEST_ERROR:
case OAuth2Properties.INVALID_GRANT_ERROR:
case OAuth2Properties.UNAUTHORIZED_CLIENT_ERROR:
case OAuth2Properties.UNSUPPORTED_GRANT_TYPE_ERROR:
case OAuth2Properties.INVALID_SCOPE_ERROR:
throw new BadRequestException(
"Malformed request: %s: %s", error.type(), error.message());
}
}
throw createRESTException(error);
}
}
}
View on GitHub (pinned to 86d9c8fc54)