alibaba/spring-ai-alibaba · error · ResponseStatusException
Thread found but belongs to a different graph/user.
Error message
Thread found but belongs to a different graph/user.
What it means
After fetching the thread, findThreadOrThrow verifies that the returned record's appName and userId match the request. A mismatch means the store returned a thread whose owner differs from the requested graph/user, and a 404 NOT_FOUND with this fixed message is thrown to avoid leaking other users' threads.
Solutions
- Ensure threadIds are globally unique (use generated IDs) and never reused across graphs or users.
- Inspect the stored Thread record and correct its appName/userId if data was seeded incorrectly.
- Verify the thread service stores/keys threads with the full (appName, userId, threadId) tuple.
- Delete the inconsistent record and recreate the thread.
Example fix
// before
createThreadWithId("my-graph", "u1", "shared-thread-id"); // same id used for another graph
// after
createThreadWithId("my-graph", "u1", UUID.randomUUID().toString()); Defensive patterns
Strategy: validation
Validate before calling
// ensure unique, non-reused thread ids client-side const threadId = crypto.randomUUID(); // never reuse across graphs/users
Try / catch
try {
await api.get(`/graphs/${graphName}/users/${userId}/threads/${threadId}`);
} catch (e) {
if (e.response?.status === 404 &&
e.response.data.includes('different graph/user')) {
// id collision or stale data: recreate thread with a fresh UUID
}
} Prevention
- Generate threadIds with UUIDs; never reuse across graphs or users.
- Do not manually seed thread records with mismatched appName/userId.
- Verify the persistence layer scopes lookups by appName and userId.
When it happens
Trigger: A persistence backend returns a Thread record for the threadId whose appName/userId fields differ from the derived GRAPH_APP_PREFIX+graphName or the requested userId — typically caused by ID collisions or inconsistent keys in the store.
Common situations: Reusing threadIds across graphs or users; manually seeded/edited persistence data with mismatched appName; a backend not scoping keys by appName/userId causing cross-tenant lookups.
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 not found: graphName=
- 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/d801567058d8e48f.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/controller/GraphThreadController.java:96
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);
return findThreadOrThrow(graphName, userId, threadId);
}
@GetMapping("/graphs/{graphName}/users/{userId}/threads")
public List<Thread> listThreads(
@PathVariable String graphName,
@PathVariable String userId) {View on GitHub (pinned to f82da0b50f)