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

  1. Treat 404 as success for idempotent deletes: catch it and consider the thread already gone.
  2. Verify the thread exists on the gateway first (gwClient/GET thread) if you need to distinguish missing vs failed.
  3. For pre-gateway local threads, delete via a non-gateway agent/context or migrate the thread to the gateway.
  4. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/02ffb0775c0c7353. Report an issue: GitHub.