spring-projects/spring-security · error · IllegalArgumentException

Token for series '<series>' does not exist

Error message

Token for series '<series>' does not exist

What it means

InMemoryTokenRepositoryImpl.updateToken looks up the token for the given series and throws IllegalArgumentException when no token with that series exists, because a token cannot be updated if it was never created.

Source

Thrown at web/src/main/java/org/springframework/security/web/authentication/rememberme/InMemoryTokenRepositoryImpl.java:51

 */
public class InMemoryTokenRepositoryImpl implements PersistentTokenRepository {

	private final Map<String, PersistentRememberMeToken> seriesTokens = new HashMap<>();

	@Override
	public synchronized void createNewToken(PersistentRememberMeToken token) {
		PersistentRememberMeToken current = this.seriesTokens.get(token.getSeries());
		if (current != null) {
			throw new DataIntegrityViolationException("Series Id '" + token.getSeries() + "' already exists!");
		}
		this.seriesTokens.put(token.getSeries(), token);
	}

	@Override
	public synchronized void updateToken(String series, String tokenValue, Date lastUsed) {
		PersistentRememberMeToken token = getTokenForSeries(series);
		if (token == null) {
			throw new IllegalArgumentException("Token for series '" + series + "' does not exist");
		}
		PersistentRememberMeToken newToken = new PersistentRememberMeToken(token.getUsername(), series, tokenValue,
				new Date());
		// Store it, overwriting the existing one.
		this.seriesTokens.put(series, newToken);
	}

	@Override
	public synchronized @Nullable PersistentRememberMeToken getTokenForSeries(String seriesId) {
		return this.seriesTokens.get(seriesId);
	}

	@Override
	public synchronized void removeUserTokens(String username) {
		Iterator<String> series = this.seriesTokens.keySet().iterator();
		while (series.hasNext()) {
			String seriesId = series.next();
			PersistentRememberMeToken token = this.seriesTokens.get(seriesId);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Check repository.getTokenForSeries(series) != null before calling updateToken.
  2. Use a persistent repository (JdbcTokenRepositoryImpl) so tokens survive restarts and in-memory loss.
  3. Treat this as an expired/unknown series: reject the remember-me cookie and force re-authentication (the framework does this by catching the exception).
  4. In tests, create the token with createNewToken before updating it.

Example fix

// before
repository.updateToken(series, newTokenValue, new Date()); // throws if series unknown
// after
if (repository.getTokenForSeries(series) != null) {
    repository.updateToken(series, newTokenValue, new Date());
} else {
    repository.createNewToken(new PersistentRememberMeToken(user, series, newTokenValue, new Date()));
}
Defensive patterns

Strategy: validation

Validate before calling

if (repo.getTokenForSeries(series) == null) {
    // unknown series: force full re-authentication instead of updating
    return null;
}

Try / catch

try {
    repo.updateToken(series, value, new Date());
} catch (IllegalArgumentException e) {
    log.info("Unknown remember-me series {}", series); // treat as expired
}

Prevention

When it happens

Trigger: Calling updateToken(series, tokenValue, lastUsed) with a series id that is not present in the in-memory map — e.g. after a server restart lost all tokens, or with a series from a cookie created by a previous deployment/repository.

Common situations: Server restarts wiping the in-memory map while users still present old remember-me cookies; pointing the app at a different repository than the one that issued the token; deleting the user's tokens (removeUserTokens) and then attempting an update; typo'd series id in custom code or tests.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/0c6dffdcac6378cb. Report an issue: GitHub.