spring-projects/spring-security · warning · IllegalArgumentException
<value>
Error message
<value>
What it means
SavedRequestAwareWrapper.getDateHeader converts date headers stored in a saved request (e.g. If-Modified-Since) using FastHttpDateFormat against several standard formats. If the saved header value cannot be parsed in any known format, it throws IllegalArgumentException with the raw value as the message. The value typically comes from a previously saved (redirected) request replayed after authentication.
Solutions
- Fix or strip the offending date header before the request is saved/replayed — validate the client sends RFC-compliant date formats (e.g. EEE, dd MMM yyyy HH:mm:ss zzz).
- Catch IllegalArgumentException around getDateHeader and treat it as an invalid/unset date header.
- Remove or ignore date headers when reconstructing the saved request, so the wrapper falls back to the original request.
- Update Spring Security if you rely on tolerant parsing — newer versions may offer more forgiving behavior; otherwise pre-parse and normalize the header yourself.
Example fix
// before
long d = wrapper.getDateHeader("If-Modified-Since");
// after
long d;
try {
d = wrapper.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException e) {
d = -1L; // treat as absent
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate a date header before use
String v = wrapper.getHeader("If-Modified-Since");
long d = (v != null) ? FastHttpDateFormat.parseDate(v, null) : -1L;
boolean valid = d != -1L; Try / catch
try {
long date = wrapper.getDateHeader("If-Modified-Since");
handle(date);
} catch (IllegalArgumentException e) {
log.warn("Unparseable date header value: {}", e.getMessage());
handle(-1L);
} Prevention
- Send dates in RFC 1123 format (EEE, dd MMM yyyy HH:mm:ss zzz)
- Strip malformed date headers from replayed saved requests
- Wrap date-header parsing in try-catch in filter code
- Test saved-request replay with edge-case headers
When it happens
Trigger: A saved request (captured before login and replayed afterward) contains a Date-type header (e.g. If-Modified-Since) whose value is not in RFC 1123/1036 or ANSI asctime format, so parseDate returns -1 and the wrapper throws.
Common situations: Browsers/clients sending malformed If-Modified-Since headers; proxies rewriting date headers into nonstandard formats; tests (expecteDateHeaderIsReturnedFromSavedRequest, invalidDateHeaderIsRejected) exercising saved-request date header handling; replayed bookmarks with stale headers manipulated by middleware.
Related errors
- A Bean named mvcHandlerMappingIntrospector of type…
- A Bean named mvcHandlerMappingIntrospector of type…
- A filter chain that matches any request
- A ReactiveSessionRegistry is needed for concurrent session…
- A ServerOneTimeTokenGenerationSuccessHandler is required to…
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/9f5ac19b1bf4fc46.
Report an issue: GitHub.
Appendix: source
Thrown at web/src/main/java/org/springframework/security/web/savedrequest/SavedRequestAwareWrapper.java:94
this.formats[1] = new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US);
this.formats[2] = new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US);
this.formats[0].setTimeZone(GMT_ZONE);
this.formats[1].setTimeZone(GMT_ZONE);
this.formats[2].setTimeZone(GMT_ZONE);
}
@Override
public long getDateHeader(String name) {
String value = getHeader(name);
if (value == null) {
return -1L;
}
// Attempt to convert the date header in a variety of formats
long result = FastHttpDateFormat.parseDate(value, this.formats);
if (result != -1L) {
return result;
}
throw new IllegalArgumentException(value);
}
@Override
public @Nullable String getHeader(String name) {
List<String> values = this.savedRequest.getHeaderValues(name);
return values.isEmpty() ? null : values.get(0);
}
@Override
public Enumeration<String> getHeaderNames() {
return new Enumerator<>(this.savedRequest.getHeaderNames());
}
@Override
public Enumeration<String> getHeaders(String name) {
return new Enumerator<>(this.savedRequest.getHeaderValues(name));
}
View on GitHub (pinned to 96852e8860)