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

  1. Make the builder mutually exclusive: set code only when present, otherwise set error/errorDescription/errorUri
  2. Sanitize the redirect URL parameters before building — prefer error fields when an error parameter exists
  3. 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

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


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)