{"record":{"id":"dedce6c0a4cd92e4","repo":"yikart/AiToEarn","slug":"session-not-found","errorCode":null,"errorMessage":"Session not found","messagePattern":"Session not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"error","filePath":"project/aitoearn-backend/libs/nest-mcp/src/services/mcp-sse.service.ts","lineNumber":110,"sourceCode":"      this.mcpServers.delete(sessionId)\n      this.pingService.removeConnection(sessionId)\n    }\n\n    await mcpServer.connect(transport)\n  }\n\n  /**\n   * Handle message processing for SSE\n   */\n  async handleMessage(rawReq: any, rawRes: any, body: unknown): Promise<any> {\n    const adapter = HttpAdapterFactory.getAdapter(rawReq, rawRes)\n    const req = adapter.adaptRequest(rawReq)\n    const res = adapter.adaptResponse(rawRes)\n    const sessionId = req.query['sessionId'] as string\n    const transport = this.transports.get(sessionId)\n\n    if (!transport) {\n      return res.status(404).send('Session not found')\n    }\n\n    const mcpServer = this.mcpServers.get(sessionId)\n    if (!mcpServer) {\n      return res.status(404).send('MCP server not found for session')\n    }\n\n    // Resolve the request-scoped tool executor service\n    const contextId = ContextIdFactory.getByRequest(req)\n    const executor = await this.moduleRef.resolve(\n      McpExecutorService,\n      contextId,\n    )\n\n    // Register request handlers with the user context from this specific request\n    executor.registerRequestHandlers(mcpServer, req)\n\n    // Process the message","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/libs/nest-mcp/src/services/mcp-sse.service.ts#L92-L128","documentation":"The MCP SSE service routes POST messages to a per-session transport held in an in-memory map. If the sessionId query parameter has no registered transport, the request is rejected with 404 'Session not found' — the client is addressing a session the server no longer knows.","triggerScenarios":"POST to the SSE message endpoint with a sessionId that was never opened, or whose SSE connection was closed/server restarted, so transports no longer contains the id.","commonSituations":"Server restart or multi-instance deployment where the SSE connection lives on another pod; client reconnecting POSTs with a stale sessionId after network drop; load balancer routing POSTs to a different instance than the GET /sse; long idle timeout closing the SSE stream while the client keeps POSTing.","solutions":["Re-establish the SSE connection (GET /sse) to obtain a fresh sessionId, then use it for POSTs","Ensure sticky sessions / same-instance routing so POSTs reach the instance holding the transport","Implement client logic to detect 404 and automatically reconnect the SSE stream","Enable SSE heartbeat/keepalive and tune timeouts so idle sessions are not dropped"],"exampleFix":"// before\nawait post(endpoint, { ...body, sessionId: storedSessionId }) // stale after restart\n// after\ntry {\n  await post(endpoint, body, { params: { sessionId } })\n} catch (e) {\n  if (isSessionNotFound(e)) { sessionId = await reconnectSse() }\n}","handlingStrategy":"retry","validationCode":"// before POSTing, confirm the SSE stream is open and the id is current\nif (!sseConnectionOpen || Date.now() - sessionIssuedAt > MAX_SESSION_TTL) {\n  sessionId = await reconnectSse()\n}","typeGuard":"function isSessionNotFound(resp: { status: number; body?: unknown }): boolean {\n  return resp.status === 404 && typeof resp.body === 'string' && resp.body.includes('Session not found')\n}","tryCatchPattern":"try {\n  await postMessage(sessionId, payload)\n} catch (e) {\n  if (isSessionNotFoundErr(e)) {\n    sessionId = await reconnectSse() // GET /sse for a new id\n    await postMessage(sessionId, payload)\n  } else { throw e }\n}","preventionTips":["Treat sessionId as ephemeral: always refresh after server restarts","Enable SSE heartbeats to keep sessions alive","Use sticky routing so POSTs hit the instance owning the session","Implement automatic reconnect on 404"],"tags":["mcp","sse","session","stateful"],"backgroundTag":"mcp-session-not-found","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}