linshenkx/prompt-optimizer · error
-32000
-32000
Error message
Bad Request: No valid session ID provided
What it means
This JSON-RPC error (code -32000) is returned as HTTP 400 by the MCP server's POST /mcp handler when the request is neither a valid InitializeRequest nor carries a known mcp-session-id. It mirrors the Streamable HTTP transport's requirement that all non-initialize requests reference an existing session.
Source
Thrown at packages/mcp-server/src/index.ts:424
enableDnsRebindingProtection: false
});
// 清理传输实例
httpTransport.onclose = () => {
if (httpTransport.sessionId) {
delete transports[httpTransport.sessionId];
}
};
// 为每个会话创建独立的服务器实例
const { server } = await createServerInstance(config);
await setupServerHandlers(server, coreServices);
// 连接到 MCP 服务器
await server.connect(httpTransport);
} else {
// 无效请求
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
});
return;
}
// 处理请求
await httpTransport.handleRequest(req, res, req.body);
});
// 处理 GET 请求(服务器到客户端通知,通过 SSE)
app.get('/mcp', async (req, res) => {
const sessionId = req.headers['mcp-session-id'] as string | undefined;
if (!sessionId || !transports[sessionId]) {View on GitHub (pinned to 3e677b1d9f)
Solutions
- Make the client perform the initialize handshake first and cache the mcp-session-id header returned by the server, sending it on every subsequent request.
- If the server restarted (sessions are in-memory), have the client re-initialize on 400/-32000 and retry.
- If a proxy/gateway sits in front, verify it forwards the mcp-session-id request and response headers.
Example fix
// before
await fetch(MCP_URL + '/mcp', { method: 'POST', body: JSON.stringify({ method: 'tools/list' }) })
// after
const init = await fetch(MCP_URL + '/mcp', { method: 'POST', body: JSON.stringify(initRequest) })
const sessionId = init.headers.get('mcp-session-id')
await fetch(MCP_URL + '/mcp', { method: 'POST', headers: { 'mcp-session-id': sessionId }, body: JSON.stringify({ method: 'tools/list' }) }) Defensive patterns
Strategy: retry
Validate before calling
if (!sessionId) {
const initRes = await fetch(MCP_URL + '/mcp', {
method: 'POST',
headers: { 'content-type': 'application/json', accept: 'application/json, text/event-stream' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'my-client', version: '1.0.0' } } })
})
sessionId = initRes.headers.get('mcp-session-id')
} Type guard
const isNoSessionError = (body: any): boolean => body?.error?.code === -32000 && /No valid session ID/.test(body?.error?.message ?? '')
Try / catch
try { await postRpc(method, params) } catch (e) { if (isNoSessionError(e)) { await reinitialize(); await postRpc(method, params) } else throw e } Prevention
- Always complete the initialize handshake before other RPCs and persist the returned mcp-session-id.
- Re-initialize and retry automatically when a 400/-32000 is received (e.g. after server restart).
- Verify proxies forward the mcp-session-id header both ways.
When it happens
Trigger: POST /mcp without an mcp-session-id header and with a body that is not a valid initialize request (e.g. a tools/call sent before initialize, a malformed initialize, or a client that lost/never stored the session ID).
Common situations: MCP client (Claude Desktop, Cursor, custom SDK client) reconnecting after a server restart — the old session ID is gone from the in-memory transports map; clients that skip the initialize handshake; proxies stripping the mcp-session-id header.
Related errors
- Invalid or missing session ID
- [BasicSystemSession] ImageStorageService is unavailable; can
- [BasicSystemSession] Failed to persist test image
- [ImageImage2ImageSession] PreferenceService is unavailable;
- [ImageImage2ImageSession] ImageStorageService is unavailable
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/2741aaa37e666fcf.
Report an issue: GitHub.