spring-projects/spring-security · error · IllegalArgumentException
code and errorCode cannot both be set
Error message
code and errorCode cannot both be set
What it means
OAuth2AuthorizationResponse.Builder.build enforces the RFC 6749 distinction between a success authorization response (must carry code, must not carry error) and an error response (must carry errorCode). Supplying both is an invalid state, so it throws IllegalArgumentException.
Solutions
- Make the builder mutually exclusive: set code only when present, otherwise set error/errorDescription/errorUri
- Sanitize the redirect URL parameters before building — prefer error fields when an error parameter exists
- In custom converters, branch: if error param present use errorCode(...), else use code(...)
Example fix
// before
builder.code(params.getFirst("code")).errorCode(params.getFirst("error"));
// after
if (StringUtils.hasText(params.getFirst("error"))) {
builder.errorCode(params.getFirst("error"));
} else {
builder.code(params.getFirst("code"));
} Defensive patterns
Strategy: validation
Validate before calling
boolean hasCode = StringUtils.hasText(code);
boolean hasError = StringUtils.hasText(errorCode);
if (hasCode == hasError) {
throw new IllegalArgumentException("Exactly one of code or errorCode must be set");
} Try / catch
catch (IllegalArgumentException e) {
if (e.getMessage().contains("code and errorCode")) {
// rebuild response preferring the error branch
}
} Prevention
- Branch builder calls on presence of the error parameter
- Never copy both code and error query params into the builder
- Sanitize redirect URL before building the response
When it happens
Trigger: Programmatically building an OAuth2AuthorizationResponse where the builder's code(...) and errorCode(...) (or error param parsing) were both invoked — e.g. a custom authorization response converter or test fixture setting both fields from a redirect URL that oddly contains both parameters.
Common situations: Custom OAuth2AuthorizationRequestRepository/converters copying all query parameters into the builder; tests hand-building responses with leftover fields; provider redirects including both code and error in one redirect.
Related errors
- Invalid Client Registration: + fieldName
- Invalid Client Registration: + fieldName
- Invalid Client Registration: + fieldName
- invalid_redirect_uri
- invalid_request
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/5ca0d69f66e6b49e.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationResponse.java:215
}
/**
* Sets the error uri.
* @param errorUri the error uri
* @return the {@link Builder}
*/
public Builder errorUri(String errorUri) {
this.errorUri = errorUri;
return this;
}
/**
* Builds a new {@link OAuth2AuthorizationResponse}.
* @return a {@link OAuth2AuthorizationResponse}
*/
public OAuth2AuthorizationResponse build() {
if (StringUtils.hasText(this.code) && StringUtils.hasText(this.errorCode)) {
throw new IllegalArgumentException("code and errorCode cannot both be set");
}
Assert.hasText(this.redirectUri, "redirectUri cannot be empty");
OAuth2AuthorizationResponse authorizationResponse = new OAuth2AuthorizationResponse();
authorizationResponse.redirectUri = this.redirectUri;
authorizationResponse.state = this.state;
if (StringUtils.hasText(this.code)) {
authorizationResponse.code = this.code;
}
else {
Assert.notNull(this.errorCode, "errorCode cannot be null when code is not present");
Assert.hasText(this.errorCode, "errorCode cannot be empty when code is not present");
authorizationResponse.error = new OAuth2Error(this.errorCode, this.errorDescription, this.errorUri);
}
return authorizationResponse;
}
}
View on GitHub (pinned to 96852e8860)