spring-projects/spring-security · error · DataIntegrityViolationException

Series Id '<series>' already exists!

Error message

Series Id '<series>' already exists!

What it means

InMemoryTokenRepositoryImpl.createNewToken refuses to overwrite an existing series and throws DataIntegrityViolationException when a PersistentRememberMeToken with the same series id is already stored. The repository mirrors the uniqueness constraint a persistent store would enforce on the series primary key.

Source

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

import org.jspecify.annotations.Nullable;

import org.springframework.dao.DataIntegrityViolationException;

/**
 * Simple <tt>PersistentTokenRepository</tt> implementation backed by a Map. Intended for
 * testing only.
 *
 * @author Luke Taylor
 */
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) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Call updateToken instead of createNewToken when the series may already exist.
  2. Remove the existing series first with removeToken/removeUserTokens before re-creating.
  3. Use JdbcTokenRepositoryImpl (with the DDL's primary key) for durable storage; treat this exception as a duplicate-key condition and generate a new series id.
  4. In tests, use a fresh InMemoryTokenRepositoryImpl per test or clear state in setup.

Example fix

// before
repository.createNewToken(new PersistentRememberMeToken(user, existingSeries, value, new Date()));
// after
if (repository.getTokenForSeries(existingSeries) != null) {
    repository.removeUserTokens(user);
}
repository.createNewToken(new PersistentRememberMeToken(user, UUID.randomUUID().toString(), value, new Date()));
Defensive patterns

Strategy: try-catch

Validate before calling

if (repo.getTokenForSeries(token.getSeries()) != null) {
    throw new IllegalStateException("series already exists: " + token.getSeries());
}

Try / catch

try {
    repo.createNewToken(token);
} catch (DataIntegrityViolationException e) {
    repo.updateToken(token.getSeries(), token.getTokenValue(), token.getDate());
}

Prevention

When it happens

Trigger: Calling createNewToken(token) twice with tokens having the same getSeries() value — typically because application code (not the framework) creates tokens manually, or two threads/instances share the same series generation without going through the repository's normal flow.

Common situations: Custom remember-me bootstrap code re-creating a token for an existing series; seeding the in-memory repository from a database that already contains the series; test code that forgets to clear the repository between cases; switching repositories (Jdbc vs InMemory) mid-flight.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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