can1357/oh-my-pi · error · MCPTransportError

No response received for request ID ${expectedId}

Error message

No response received for request ID ${expectedId}

What it means

The transport POSTed a JSON-RPC request, the server accepted it and opened an SSE stream, but the stream ended (EOF) without ever delivering a JSON-RPC response matching the expected request id, and no event id was supplied so the stream cannot be resumed. The transport deliberately does not replay the POST because the request may already have executed a state-changing tool on the server; it throws a non-retryable receive-stage error instead.

Source

Thrown at packages/coding-agent/src/mcp/transports/http.ts:616

							}
						}
					} catch (error) {
						// An abrupt drop (socket reset, body-read failure) is as
						// resumable as a server-initiated close once an event ID
						// exists; the request timeout still bounds the total wait.
						if (captured) return;
						if (signal.aborted || resume.lastEventId === null) throw error;
						logger.debug("MCP SSE response stream dropped; resuming", {
							url: this.config.url,
							error: error instanceof Error ? error.message : String(error),
						});
					}
					if (captured) return;
					if (signal.aborted) {
						throw signal.reason ?? new DOMException("MCP SSE response aborted", "AbortError");
					}
					if (resume.lastEventId === null) {
						throw new MCPTransportError({
							transport: "http",
							stage: "receive",
							failure: "eof",
							message: `No response received for request ID ${expectedId}`,
							retryable: false,
							traceId,
						});
					}
					current = await this.#fetchSSEResume(resume, signal);
				}
			} catch (error) {
				if (captured) return;
				// The server accepted this POST (it returned a 2xx SSE stream) before
				// the drain or a resume GET failed, so the originating request must
				// never be replayed — it may already have executed a state-changing
				// tool. Preserve SSEResumeError so #requestWithAuthRetry's no-replay
				// guard still fires instead of refreshing auth and re-POSTing, and
				// force every other post-acceptance failure non-retryable so the

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the MCP server logs around the trace id for a crash or unhandled error in the request handler and fix the handler to always emit a JSON-RPC response.
  2. Verify whether the side effect (tool call) actually executed; if the operation is idempotent, re-issue the request explicitly.
  3. Increase server-side request timeouts so the server does not close the stream before the handler completes.
  4. Fix proxies to keep streaming connections alive (proxy_read_timeout, disable idle connection reaping).
  5. Update the MCP server — every accepted request must produce exactly one response message on the SSE stream.

Example fix

// server handler (before): early return skips sending the JSON-RPC reply
if (!resource) return;
sendResult(id, result);
// after: always answer the pending request
if (!resource) { sendError(id, { code: -32602, message: 'not found' }); return; }
sendResult(id, result);
Defensive patterns

Strategy: try-catch

Validate before calling

// no pre-call check can detect a dropped response; monitor stream health instead
const ok = await fetch(url, { method: 'OPTIONS' }).then(r => r.ok).catch(() => false);
if (!ok) throw new Error('MCP endpoint unreachable — skip request');

Type guard

function isMissingResponseError(e: unknown): e is MCPTransportError {
  return e instanceof MCPTransportError && e.failure === 'eof' && e.stage === 'receive' &&
    /No response received for request ID/.test(e.message);
}

Try / catch

try {
  result = await client.request('tools/call', { name, args });
} catch (e) {
  if (isMissingResponseError(e)) {
    // request MAY have executed; check server state before re-running
    result = await confirmOrReplayIdempotent(name, args);
  } else throw e;
}

Prevention

When it happens

Trigger: Server closes the SSE stream after processing the tool but before writing the response; server crashes mid-request; stream interrupted on first physical connection with no SSE id: field ever sent; handler silently fails without sending a reply.

Common situations: MCP server bugs where an exception in the tool handler drops the response; server timeouts shorter than the client's; network cut on the first event frame; servers behind proxies that sever idle streams before the response is emitted.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/afe324c7615e4971. Report an issue: GitHub.