alibaba/spring-ai-alibaba · error · IllegalStateException
Thread already exists:
Error message
Thread already exists:
What it means
ThreadServiceImpl.createThread builds a map key from appName/userId/threadId and throws IllegalStateException when the in-memory threads map already contains that key. The library enforces thread-ID uniqueness per app/user, refusing to silently overwrite an existing conversation thread. Callers must generate a fresh threadId or reuse the existing thread instead of calling createThread again.
Source
Thrown at spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/service/ThreadServiceImpl.java:90
return ListThreadsResponse.of(userThreads);
});
}
@Override
public Mono<Thread> createThread(
String appName, String userId, Map<String, Object> initialState, String threadId) {
return Mono.fromCallable(() -> {
// Generate thread ID if not provided
String finalThreadId = (threadId == null || threadId.trim().isEmpty())
? generateThreadId()
: threadId;
String key = buildKey(appName, userId, finalThreadId);
// Check if thread already exists
if (threads.containsKey(key)) {
log.warn("Attempted to create duplicate thread: {}", finalThreadId);
throw new IllegalStateException("Thread already exists: " + finalThreadId);
}
// Create new thread
Thread newThread = Thread.builder(finalThreadId)
.appName(appName)
.userId(userId)
.build();
threads.put(key, newThread);
// Store initial state if provided
if (initialState != null && !initialState.isEmpty()) {
thradStates.put(key, new ConcurrentHashMap<>(initialState));
}
log.info("Created thread: {} for app={}, user={}", finalThreadId, appName, userId);
return newThread;
});View on GitHub (pinned to f82da0b50f)
Solutions
- Generate a unique threadId (e.g., UUID.randomUUID()) per conversation before calling createThread.
- Check thread existence first via a get/threads lookup (or the same buildKey containsKey check) and reuse the existing thread instead of creating.
- If retrying after failure, use the same threadId only when the previous create truly succeeded, otherwise issue a new threadId.
- Wrap the call in try-catch for IllegalStateException and treat it as 'thread already initialized' by fetching the existing thread.
Example fix
// before threadService.createThread(appName, userId, "main-thread"); // throws on restart/retry // after String threadId = UUID.randomUUID().toString(); threadService.createThread(appName, userId, threadId);
Defensive patterns
Strategy: try-catch
Validate before calling
if (threadService.getThread(appName, userId, threadId) != null) { /* reuse existing */ } Try / catch
try {
threadService.createThread(appName, userId, threadId);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Thread already exists")) {
// reuse existing thread
} else { throw e; }
} Prevention
- Always generate threadId with UUID.randomUUID() per conversation
- Check thread existence before creating
- Make create calls idempotent on the caller side so retries don't re-create
When it happens
Trigger: Calling ThreadService.createThread with (appName, userId, threadId) triple whose key already exists in the threads map — i.e., a second createThread call with the same threadId for the same app and user.
Common situations: Client retry after a timeout re-sends the same create request; a caller that saved the threadId and re-runs initialization code on restart; frontend generating a fixed threadId instead of a UUID per conversation; race where two requests create the same threadId concurrently (the warn log 'Attempted to create duplicate thread' indicates this path).
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
- Thread already exists:
- Thread already exists:
- Instruction is empty and shareState is false
- Either 'instruction' or 'includeContents' must be set for Ag
- Last message is neither an AssistantMessage nor a ToolRespon
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/97ccbabd4b8fe17e.
Report an issue: GitHub.