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

  1. Call GET /apps/{appName}/users/{userId}/threads to list existing threads and confirm the exact appName/userId/threadId
  2. Create the thread first via POST /apps/{appName}/users/{userId}/threads/{threadId} before reading it
  3. Configure a persistent thread store (Redis/DB) instead of in-memory if threads must survive restarts
  4. Verify the path variables match the values used at creation time (case-sensitive)
  5. 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

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


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/3cc45ea773ea608d. Report an issue: GitHub.