spring-projects/spring-security · error · IllegalArgumentException
Expression was null but expected boolean result '{expression
Error message
Expression was null but expected boolean result '{expressionString}' What it means
Spring Security's ExpressionUtils.evaluateAsBoolean evaluates a SpEL security expression (e.g. from @PreAuthorize) expecting a Boolean result. If the expression evaluates to null instead of true/false, the library throws IllegalArgumentException because authorization requires a definitive boolean answer. This typically happens when the expression returns a null value (e.g. calling a method or accessing a property that yields null).
Source
Thrown at core/src/main/java/org/springframework/security/access/expression/ExpressionUtils.java:32
* limitations under the License.
*/
package org.springframework.security.access.expression;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
public final class ExpressionUtils {
private ExpressionUtils() {
}
public static boolean evaluateAsBoolean(Expression expr, EvaluationContext ctx) {
try {
Boolean result = expr.getValue(ctx, Boolean.class);
if (result == null) {
throw new IllegalArgumentException(
"Expression was null but expected boolean result '" + expr.getExpressionString() + "'");
}
return result;
}
catch (EvaluationException ex) {
throw new IllegalArgumentException("Failed to evaluate expression '" + expr.getExpressionString() + "'",
ex);
}
}
}
View on GitHub (pinned to 96852e8860)
Solutions
- Change the security expression so it always returns a boolean, e.g. wrap null-able calls: @bean.findUser() != null and @bean.findUser().active
- Use null-safe SpEL operators (?.) in the expression so comparisons yield true/false instead of null
- If you own the called method, return Boolean.FALSE instead of null when the check fails
- Catch IllegalArgumentException around the authorization call and treat it as a denial with a clearer message
Example fix
// before
@PreAuthorize("@permService.checkAccess(#doc)")
// after
@PreAuthorize("@permService.checkAccess(#doc) == true") // or make checkAccess return boolean, never null Defensive patterns
Strategy: validation
Validate before calling
Boolean val = expr.getValue(ctx, Boolean.class);
if (val == null) throw new IllegalStateException("Expression '" + expr.getExpressionString() + "' must not return null"); Type guard
if (expr.getValue(ctx) instanceof Boolean b) { /* safe to authorize */ } Try / catch
try { ExpressionUtils.evaluateAsBoolean(expr, ctx); }
catch (IllegalArgumentException e) { denyAccess(); } Prevention
- Make every security-expression target method return primitive boolean
- Use == true comparison in @PreAuthorize to coerce null checks
- Use SpEL ?. and ?: operators for null-able paths
- Unit-test security expressions against null-returning services
When it happens
Trigger: Calling ExpressionUtils.evaluateAsBoolean(expr, ctx) where expr.getValue(ctx, Boolean.class) returns null — e.g. a @PreAuthorize expression like "@bean.method()" whose return value is null, or a property access resolving to null.
Common situations: Custom authorization expressions invoking service/bean methods that return null instead of boolean; security expressions referencing missing properties on the root object; refactoring a check from 'hasRole(...)' to a custom check that returns null on some paths.
Related errors
- Failed to evaluate expression '{expressionString}'
- Access is denied
- Security interception failed due to: %s; secure object: %s;
- Security authorization failed due to: %s; authenticated prin
- Access is denied
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/f6080c35c6a6496d.
Report an issue: GitHub.