alibaba/spring-ai-alibaba · error · ResponseStatusException
Thread not found: graphName=
Error message
Thread not found: graphName=%s, userId=%s, threadId=%s
What it means
findThreadOrThrow looks up a thread by appName (derived from graphName), userId, and threadId via threadService.getThread(...).block(). If the result is absent it throws a 404 NOT_FOUND ResponseStatusException with a formatted message naming all three keys.
Solutions
- Confirm the threadId was created previously via the create-thread endpoint for the same graph and user.
- Check userId and graphName match the ones used at thread creation.
- Verify the thread persistence store is running and configured correctly (empty lookups can stem from backend failures).
- List threads for the user to find valid threadIds.
Example fix
// before
const t = await api.get(`/graphs/my-graph/users/u1/threads/${threadId}`); // never created
// after
const created = await api.post(`/graphs/my-graph/users/u1/threads`, {});
const t = await api.get(`/graphs/my-graph/users/u1/threads/${created.threadId}`); Defensive patterns
Strategy: validation
Validate before calling
// before fetching a thread
const threads = await api.get(`/graphs/${graphName}/users/${userId}/threads`);
if (!threads.some(t => t.threadId === threadId)) {
throw new Error(`Thread ${threadId} does not exist for this graph/user`);
} Try / catch
try {
await api.get(`/graphs/${graphName}/users/${userId}/threads/${threadId}`);
} catch (e) {
if (e.response?.status === 404) { /* create the thread or use a listed threadId */ }
} Prevention
- Only use threadIds returned by thread-creation or list endpoints.
- Keep (graphName, userId, threadId) triples consistent client-side.
- Ensure the thread persistence backend is healthy and configured.
When it happens
Trigger: GET /graphs/{graphName}/users/{userId}/threads/{threadId} or createThreadWithId where no thread exists with that exact (graphName→appName, userId, threadId) triple, or the blocking lookup returns empty/null.
Common situations: Thread was already deleted; wrong threadId (e.g. client-generated ID never created); thread belongs to a different user; persistence backend (Mongo/Redis/etc.) not reachable so lookups return empty; retrying with an ID from another environment.
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
- Graph not found:
- Graph not found:
- Thread found but belongs to a different graph/user.
- APP_COMPONENT_QUERYCONFIG_ERROR
- APP_COMPONENT_REFER_ERROR
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/db3c05fd118e7f14.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/controller/GraphThreadController.java:89
return GRAPH_APP_PREFIX + graphName;
}
private void validateGraphExists(String graphName) {
if (graphName == null || graphName.isBlank()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "graphName cannot be null or empty");
}
if (!graphLoader.listGraphs().contains(graphName)) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Graph not found: " + graphName);
}
}
private Thread findThreadOrThrow(String graphName, String userId, String threadId) {
String appName = toAppName(graphName);
Optional<Thread> optionalThread =
threadService.getThread(appName, userId, threadId, Optional.empty()).block();
if (optionalThread == null || !optionalThread.isPresent()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
String.format("Thread not found: graphName=%s, userId=%s, threadId=%s",
graphName, userId, threadId));
}
Thread thread = optionalThread.get();
if (!Objects.equals(thread.appName(), appName) || !Objects.equals(thread.userId(), userId)) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
"Thread found but belongs to a different graph/user.");
}
return thread;
}
@GetMapping("/graphs/{graphName}/users/{userId}/threads/{threadId}")
public Thread getThread(
@PathVariable String graphName,
@PathVariable String userId,
@PathVariable String threadId) {
validateGraphExists(graphName);View on GitHub (pinned to f82da0b50f)