{"record":{"id":"0e47ecae6adbd34d","repo":"mastra-ai/mastra","slug":"bad-request-req-method-request-requires-a-vali","errorCode":null,"errorMessage":"Bad Request: ${req.method} request requires a valid session ID","messagePattern":"Bad Request: (.+?) request requires a valid session ID","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"packages/mcp/src/server/server.ts","lineNumber":2225,"sourceCode":"          } else {\n            // POST request but not initialize, and no session ID\n            this.logger.warn('Received non-initialize POST request without session ID');\n            res.writeHead(400, { 'Content-Type': 'application/json' });\n            res.end(\n              JSON.stringify({\n                jsonrpc: '2.0',\n                error: {\n                  code: -32000,\n                  message: 'Bad Request: No valid session ID provided for non-initialize request',\n                },\n                id: (body as any)?.id ?? null, // Include original request ID if available\n              }),\n            );\n          }\n        } else {\n          // Non-POST request (GET/DELETE) without a session ID\n          this.logger.warn('Received request without session ID', { method: req.method });\n          res.writeHead(400, { 'Content-Type': 'application/json' });\n          res.end(\n            JSON.stringify({\n              jsonrpc: '2.0',\n              error: {\n                code: -32000,\n                message: `Bad Request: ${req.method} request requires a valid session ID`,\n              },\n              id: null,\n            }),\n          );\n        }\n      }\n    } catch (error) {\n      const mastraError = new MastraError(\n        {\n          id: 'MCP_SERVER_HTTP_CONNECTION_FAILED',\n          domain: ErrorDomain.MCP,\n          category: ErrorCategory.USER,","sourceCodeStart":2207,"sourceCodeEnd":2243,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/mcp/src/server/server.ts#L2207-L2243","documentation":"The MCPServer's streamable-HTTP handler rejects GET or DELETE requests that arrive without a valid `mcp-session-id` header. The streamable HTTP transport is sessionful: only the initial `initialize` POST can run without a session; every subsequent request (including SSE GET streams and session-terminating DELETEs) must carry the session ID returned during initialize. The server responds with HTTP 400 and JSON-RPC code -32000.","triggerScenarios":"Calling the MCP HTTP endpoint with GET (to open an SSE stream) or DELETE (to close a session) while omitting the `mcp-session-id` header; a client that never performed the `initialize` handshake; a proxy/gateway stripping custom headers; a client reusing a base URL without persisting the session ID; server restart that lost in-memory `streamableHTTPTransports` while the client still sends its old session ID (that variant surfaces as the sibling 'No valid session ID provided' error for POST).","commonSituations":"Hand-rolled HTTP clients or curl probes that hit the GET endpoint directly without initializing; third-party MCP clients behind header-stripping corporate proxies; serverless/edge deployments where in-memory session maps don't survive between invocations (stateless mode should be used instead); load balancers routing follow-up requests to a different replica than the one holding the session.","solutions":["Perform the `initialize` JSON-RPC POST first and capture the session ID from the `mcp-session-id` response header.","Send that session ID back as the `mcp-session-id` header on every subsequent GET/DELETE/POST request.","If your deployment is serverless or multi-instance, enable the serverless/stateless request path (sessionIdGenerator: undefined / handleServerlessRequest) so no session state is required.","Verify no proxy, API gateway, or middleware strips the `mcp-session-id` header.","If the server restarted, re-initialize the session instead of reusing a stale session ID."],"exampleFix":"// before\ncurl -X GET http://localhost:4111/mcp\n// after\nSESSION=$(curl -s -D - -X POST http://localhost:4111/mcp -H 'Content-Type: application/json' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"x\",\"version\":\"1\"}}}' \\\n  | grep -i mcp-session-id | awk '{print $2}' | tr -d '\\r')\ncurl -X GET http://localhost:4111/mcp -H \"mcp-session-id: $SESSION\"","handlingStrategy":"validation","validationCode":"const sid = headers['mcp-session-id'];\nif (!sid && !isInitializeRequest(body)) {\n  throw new Error('mcp-session-id header required for non-initialize MCP requests');\n}","typeGuard":"function hasSessionId(h: Record<string, string | string[] | undefined>): h is Record<string, string> & { 'mcp-session-id': string } {\n  return typeof h['mcp-session-id'] === 'string' && h['mcp-session-id'].length > 0;\n}","tryCatchPattern":"try {\n  const res = await fetch(mcpUrl, { method: 'GET', headers: { 'mcp-session-id': sessionId } });\n  if (res.status === 400) {\n    const err = await res.json();\n    if (err.error?.code === -32000) sessionId = await reinitialize();\n  }\n} catch (e) { /* retry with fresh initialize */ }","preventionTips":["Always run the initialize handshake before any GET/DELETE/POST-followup request.","Persist the mcp-session-id header value from the initialize response and attach it to every request.","Use an official MCP client SDK instead of raw HTTP calls so session handling is automatic.","Check proxies/gateways for custom-header stripping rules.","For multi-instance or serverless deployments, use the stateless/serverless server mode."],"tags":["http","mcp","session","bad-request"],"backgroundTag":"missing-mcp-session-id","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}