mastra-ai/mastra · error
SSE connection not established
Error message
SSE connection not established
What it means
In the SSE (legacy) transport integration, POSTs to the messagePath are handled by the stored sseTransport instance, which only exists after a client opened the SSE endpoint. If a POST arrives before any SSE connection was established, the server responds 503 with the plain-text body 'SSE connection not established' instead of processing the message.
Source
Thrown at packages/mcp/src/server/server.ts:1847
* });
* });
*
* httpServer.listen(1234, () => {
* console.log('MCP server listening on http://localhost:1234/sse');
* });
* ```
*/
public async startSSE({ url, ssePath, messagePath, req, res }: MCPServerSSEOptions): Promise<void> {
try {
if (url.pathname === ssePath) {
await this.connectSSE({
messagePath,
res,
});
} else if (url.pathname === messagePath) {
this.logger.debug('Received message');
if (!this.sseTransport) {
res.writeHead(503);
res.end('SSE connection not established');
return;
}
// Check for pre-parsed body from middleware like express.json()
// If not available, let the SDK's handlePostMessage read from the stream
// (which has built-in size limits and charset handling)
const parsedBody = await this.readJsonBody(req, { preParsedOnly: true });
await this.sseTransport.handlePostMessage(req, res, parsedBody);
} else {
this.logger.debug('Unknown path:', { path: url.pathname });
res.writeHead(404);
res.end();
}
} catch (e) {
const mastraError = new MastraError(
{
id: 'MCP_SERVER_SSE_START_FAILED',
domain: ErrorDomain.MCP,View on GitHub (pinned to 75dd419e61)
Solutions
- Establish the SSE connection (GET on ssePath) and wait for the endpoint/event message before POSTing to messagePath
- Ensure both SSE and message paths are routed to the same server instance (sticky sessions / single instance)
- Fix client configuration so the MCP SDK's SSE client (which sequences SSE then POST) is used instead of hand-rolled requests
- Check proxies/load balancers for SSE timeouts or buffering that kill the connection
Defensive patterns
Strategy: retry
Try / catch
async function postMessage(url, body, retries = 3) {
for (let i = 0; i < retries; i++) {
const res = await fetch(url, { method: 'POST', body });
if (res.status !== 503) return res;
await new Promise(r => setTimeout(r, 500 * (i + 1))); // SSE may not be open yet
}
throw new Error('SSE connection never established; check client transport setup');
} Prevention
- Use the official MCP SDK SSE client, which opens the SSE stream before sending messages
- Verify the SSE GET endpoint returns 200 and an endpoint event before POSTing
- Configure sticky sessions in multi-instance deployments so SSE and POST hit the same instance
- Monitor for proxy/LB configurations that terminate idle SSE connections
When it happens
Trigger: POSTing a JSON-RPC message to the messagePath endpoint when no GET request to the ssePath has completed; race where a client sends its initialize message before the SSE stream is connected; load balancer routing the POST to a different instance than the one holding the SSE connection.
Common situations: curl-based testing that POSTs to /message without first opening the SSE stream; clients constructed with the wrong SSE URL so the stream never opens; multi-instance deployments without sticky sessions; SSE connection dropped (proxy timeout) while the client keeps POSTing.
Related errors
- Could not connect to server with any available HTTP transpor
- MCPClientServerProxy does not support SSE transport
- MCPClientServerProxy does not support Hono SSE transport
- heartbeatMs must be a finite number no greater than ${MAX_TI
- @mastra/livekit: Mastra agent stream returned an empty respo
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/bc55a13121d2d3ba.
Report an issue: GitHub.