alibaba/spring-ai-alibaba · error · ResponseStatusException
Thread not found: appName=%s, userId=%s, threadId=%s
Error message
Thread not found: appName=%s, userId=%s, threadId=%s
What it means
ThreadController.findThreadOrThrow throws 404 NOT_FOUND with appName/userId/threadId detail when threadService.getThread returns no Thread for that triple. This is the standard 'thread does not exist' signal for GET /apps/{appName}/users/{userId}/threads/{threadId} and as the pre-check inside createThreadWithId.
Source
Thrown at spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/controller/ThreadController.java:80
/**
* Finds a thread by its identifiers or throws a ResponseStatusException if not found or if
* there's an app/user mismatch.
*
* @param appName The application name.
* @param userId The user ID.
* @param threadId The thread ID.
* @return The found Thread object.
* @throws ResponseStatusException with HttpStatus.NOT_FOUND if the thread doesn't exist or
* belongs to a different app/user.
*/
private Thread findThreadOrThrow(String appName, String userId, String threadId) {
Optional<Thread> optionalThread =
threadService.getThread(appName, userId, threadId, Optional.empty()).block();
if (optionalThread == null || !optionalThread.isPresent()) {
log.warn(
"Thread not found for appName={}, userId={}, threadId={}", appName, userId, threadId);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND,
String.format(
"Thread not found: appName=%s, userId=%s, threadId=%s",
appName, userId, threadId));
}
Thread thread = optionalThread.get();
if (!Objects.equals(thread.appName(), appName) || !Objects.equals(thread.userId(), userId)) {
log.warn(
"Thread ID {} found but appName/userId mismatch (Expected: {}/{}, Found: {}/{}) -"
+ " Treating as not found.",
threadId,
appName,
userId,
thread.appName(),
thread.userId());
View on GitHub (pinned to f82da0b50f)
Solutions
- Call GET /apps/{appName}/users/{userId}/threads to list existing threads and confirm the exact appName/userId/threadId
- Create the thread first via POST /apps/{appName}/users/{userId}/threads/{threadId} before reading it
- Configure a persistent thread store (Redis/DB) instead of in-memory if threads must survive restarts
- Verify the path variables match the values used at creation time (case-sensitive)
- Handle 404 in the client and re-create the thread as part of session recovery
Example fix
// before Thread t = GET /apps/myapp/users/u1/threads/old-id; // 404 after restart // after List<Thread> threads = GET /apps/myapp/users/u1/threads; String id = threads.isEmpty() ? createThread().threadId() : threads.get(0).threadId();
Defensive patterns
Strategy: validation
Validate before calling
// verify thread exists before use
List<Map> threads = restTemplate.getForObject("/apps/{a}/users/{u}/threads", List.class, app, user);
boolean exists = threads.stream().anyMatch(t -> threadId.equals(((Map) t).get("threadId")));
if (!exists) { threadId = createThread(); } Try / catch
try { return getThread(id); } catch (HttpClientErrorException.NotFound e) { return createNewThread(); } Prevention
- Treat thread IDs as ephemeral across studio restarts unless persistent storage is configured
- Always fetch the thread list to validate IDs after redeploys
- Keep appName/userId values consistent (exact case) between calls
- Recover sessions by re-creating threads on 404
When it happens
Trigger: GET a threadId that was never created; referencing a thread after the server restarted with an in-memory (non-persistent) thread store; wrong appName or userId in the path; thread deleted by another request.
Common situations: Client caching stale thread IDs across studio restarts; typo in appName/userId path segments; using a thread created under /graphs/... routes with the /apps/... routes backed by a different store; in-memory storage lost on redeploy.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Thread found but belongs to a different app/user.
- Thread already exists:
- Failed to create thread
- Thread already exists:
- Failed to create thread (null result)
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/3cc45ea773ea608d.
Report an issue: GitHub.