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

  1. 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).
  2. Catch IllegalArgumentException around getDateHeader and treat it as an invalid/unset date header.
  3. Remove or ignore date headers when reconstructing the saved request, so the wrapper falls back to the original request.
  4. 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

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


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)