{"record":{"id":"25530d5f85ccfd03","repo":"apache/shardingsphere","slug":"session-does-not-exist","errorCode":null,"errorMessage":"Session does not exist.","messagePattern":"Session does not exist\\.","errorType":"exception","errorClass":"MCPSessionNotExistedException","httpStatus":null,"severity":"error","filePath":"mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/session/MCPSessionManager.java","lineNumber":133,"sourceCode":"            if (sessionState == sessions.get(sessionId)) {\n                try {\n                    notifySessionCloseListeners(sessionId);\n                } finally {\n                    sessions.remove(sessionId, sessionState);\n                }\n            }\n        }\n    }\n    \n    ReentrantLock findExecutionLock(final String sessionId) {\n        SessionState sessionState = sessions.get(sessionId);\n        return null == sessionState ? null : sessionState.executionLock;\n    }\n    \n    ReentrantLock getRequiredExecutionLock(final String sessionId) {\n        ReentrantLock result = findExecutionLock(sessionId);\n        if (null == result) {\n            throw new MCPSessionNotExistedException();\n        }\n        return result;\n    }\n    \n    Set<String> getSessionIds() {\n        return new LinkedHashSet<>(sessions.keySet());\n    }\n    \n    private SessionState getRequiredSessionState(final String sessionId) {\n        SessionState result = sessions.get(sessionId);\n        if (null == result) {\n            throw new MCPSessionNotExistedException();\n        }\n        return result;\n    }\n    \n    private void notifySessionCloseListeners(final String sessionId) {\n        for (Consumer<String> each : sessionCloseListeners) {","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/session/MCPSessionManager.java#L115-L151","documentation":"MCPSessionManager.getRequiredExecutionLock looks up the per-session state (which owns a ReentrantLock serializing executions); when no SessionState exists for the sessionId it throws MCPSessionNotExistedException ('Session does not exist.'). This fires when an execution is requested against a session id the manager no longer tracks — never initialized, already closed, or removed after server restart. It is the generic unknown-session guard for any code path requiring the session's execution lock.","triggerScenarios":"Invoking a tool that runs under the session execution lock with a session id that is absent from the sessions map: an id from a previous server process, an id removed by closeSession/remove, or a fabricated/garbled Mcp-Session-Id header value.","commonSituations":"Server restart or redeploy while a long-lived client keeps using an old session id; session expired/closed due to inactivity timeout; load balancer routing requests to a node that never hosted the session; client losing the initialize response and guessing an id.","solutions":["Re-run the MCP initialize handshake and use the newly returned session id.","Confirm the Mcp-Session-Id header is sent verbatim from the InitializeResult on every subsequent request.","If deployed with multiple nodes, ensure sticky routing or shared session state for HTTP transport.","Handle the session-not-existed error code in the client as a signal to transparently re-initialize."],"exampleFix":"// before\nconst sessionId = loadFromDisk() ?? 'guess-1234'; // stale after server restart\nawait mcp.callTool(sessionId, 'database_gateway_execute_query', args); // Session does not exist.\n\n// after\nasync function withSession(mcp, args) {\n  try { return await mcp.callTool(getSessionId(), 'database_gateway_execute_query', args); }\n  catch (e) { if (e.code === 'SESSION_NOT_EXISTED') { setSessionId(await mcp.initialize());\n              return mcp.callTool(getSessionId(), 'database_gateway_execute_query', args); } throw e; }\n}","handlingStrategy":"retry","validationCode":"// Confirm the session is alive before issuing tool calls\nconst ids = await mcp.request('sessions/list'); // where exposed; else rely on initialize bookkeeping\nif (!ids.includes(sessionId)) sessionId = (await mcp.request('initialize', initParams)).sessionId;","typeGuard":null,"tryCatchPattern":"try {\n  return await callToolWithSession(sessionId, tool, args);\n} catch (e) {\n  if (e.message === 'Session does not exist.' || e.code === 'SESSION_NOT_EXISTED') {\n    sessionId = (await mcp.request('initialize', initParams)).sessionId; // re-handshake once\n    return callToolWithSession(sessionId, tool, args);\n  }\n  throw e;\n}","preventionTips":["Persist the session id immediately after initialize and never fabricate one.","Treat server restarts/deploys as implicit session invalidation; re-initialize on reconnect.","Implement single automatic re-initialize-and-retry on session-not-existed.","With multiple server nodes, use sticky routing so the session-bearing node receives requests."],"tags":["mcp","session","lifecycle","initialize"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}