mastra-ai/mastra · error · HTTPException
Thread not found on gateway
Error message
Thread not found on gateway
What it means
DELETE /memory/threads/:threadId, on the gateway-agent path, calls `gwClient.deleteThread`. If the gateway response is not ok, the handler throws HTTP 404 'Thread not found on gateway' — specifically indicating the delete failed at the gateway because no such thread exists there (as opposed to local storage).
Source
Thrown at packages/server/src/server/handlers/memory.ts:1568
const agent = await getAgentFromContext({ mastra, agentId, requestContext });
if (agent && (await isGatewayAgentAsync(agent))) {
const gwClient = getGatewayClient();
if (gwClient) {
// Validate ownership before deleting
const existing = await gwClient.getThread(effectiveThreadId!);
if (existing) {
await enforceThreadAccess({
mastra,
requestContext,
threadId: effectiveThreadId!,
thread: toLocalThread(existing.thread),
effectiveResourceId,
permission: MastraFGAPermissions.MEMORY_DELETE,
});
}
const deleteResult = await gwClient.deleteThread(effectiveThreadId!);
if (!deleteResult.ok) {
throw new HTTPException(404, { message: 'Thread not found on gateway' });
}
return { result: 'Thread deleted' };
}
}
const memory = await getMemoryFromContext({ mastra, agentId, requestContext });
if (!memory) {
throw new HTTPException(400, { message: 'Memory is not initialized' });
}
const thread = await memory.getThreadById({ threadId: effectiveThreadId! });
if (!thread) {
throw new HTTPException(404, { message: 'Thread not found' });
}
await enforceThreadAccess({
mastra,
requestContext,
threadId: effectiveThreadId!,View on GitHub (pinned to 75dd419e61)
Solutions
- Treat 404 as success for idempotent deletes: catch it and consider the thread already gone.
- Verify the thread exists on the gateway first (gwClient/GET thread) if you need to distinguish missing vs failed.
- For pre-gateway local threads, delete via a non-gateway agent/context or migrate the thread to the gateway.
- Check gateway client configuration to ensure you target the environment where the thread lives.
Example fix
// before
await client.deleteThread(threadId); // throws 404 if already gone
// after
try {
await client.deleteThread(threadId);
} catch (e) {
if (e.status !== 404) throw e; // idempotent delete
} Defensive patterns
Strategy: fallback
Validate before calling
const existing = await gwClient.getThread(threadId);
if (!existing) {
return { alreadyDeleted: true }; // nothing to delete on gateway
} Try / catch
try {
await client.deleteThread(threadId);
} catch (e) {
if (isHttpError(e) && e.status === 404 && /gateway/.test(e.message)) {
// treat as already-deleted (idempotent); optionally fall back to local deletion
} else throw e;
} Prevention
- Make deletes idempotent: a 404 means the goal state is already reached.
- After gateway migration, delete legacy local threads through the local path or migrate them first.
- Verify gateway environment/project config before destructive operations.
- Guard UI delete buttons against double-submission to avoid confusing 404s.
When it happens
Trigger: DELETE /api/memory/threads/:threadId with ?agentId= of a gateway-backed agent where the threadId was never created on the gateway or was already deleted; also non-ok gateway responses surfaced as this 404.
Common situations: Threads created locally before gateway migration being deleted through the gateway path; double-delete (idempotency gaps) from retrying UI actions; gateway pointed at a different environment than where the thread exists.
Related errors
- Model "${modelId}" is not available. Available models: ${ids
- ACP connection is not initialized
- Model "${this.options.model}" is not available. Available mo
- ClaudeSDKAgent resumeData must include either sessionId or c
- ClaudeSDKAgent resumeData.sessionId must be a string.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/02ffb0775c0c7353.
Report an issue: GitHub.