can1357/oh-my-pi · error · MCPTransportError

Notify timeout after ${timeout}ms

Error message

Notify timeout after ${timeout}ms

What it means

The notification POST exceeded the configured MCP timeout. The fetch (or body read for piggybacked SSE data) was aborted by the timeout controller, detected via operation.isTimeoutAbort, and rethrown as a timeout-stage MCPTransportError that is explicitly non-retryable — notifications have no response, so a timeout cannot distinguish delivered from undelivered and a blind replay could double-apply side effects.

Source

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

			if (contentType.includes("text/event-stream") && response.body) {
				// Use the SSE connection's signal if available; otherwise keep the existing finite read timeout.
				if (this.#sseConnection) {
					this.#trackBackgroundDrain(
						this.#readSSEStream(response.body, this.#operationSignal(this.#sseConnection.signal)),
					);
				} else {
					const readOperation = createMCPTimeout(timeout, this.#operationSignal());
					const signal = readOperation.signal ?? getNeverAbortSignal();
					this.#trackBackgroundDrain(
						this.#readSSEStream(response.body, signal).finally(() => readOperation.clear()),
					);
				}
			} else {
				await response.body?.cancel();
			}
		} catch (error) {
			if (operation.isTimeoutAbort(error)) {
				throw new MCPTransportError({
					transport: "http",
					stage,
					failure: "timeout",
					message: `Notify timeout after ${timeout}ms`,
					retryable: false,
					traceId,
					cause: error,
				});
			}
			if (error instanceof Error && error.name === "AbortError") throw error;
			throw normalizeMCPTransportError(error, { transport: "http", stage, traceId });
		} finally {
			operation.clear();
		}
	}

	close(): Promise<void> {
		if (this.#closePromise) return this.#closePromise;

View on GitHub (pinned to 9690622007)

Solutions

  1. Raise the MCP timeout configuration (config.timeout) if the server legitimately takes longer than the current limit.
  2. Check server load/latency and fix the slow handler blocking the notification path.
  3. Verify network path health (proxies, VPN) for stalls; the error includes a traceId to correlate with server logs.
  4. Do not auto-retry this error: confirm on the server whether the notification was applied before resending, to avoid duplicate effects.
  5. If notifications routinely time out, switch the server to return 202 immediately and process asynchronously.

Example fix

// before: default/aggressive timeout
const transport = new HttpTransport({ url, timeout: 5000 });
// after: headroom for slow notification acceptance
const transport = new HttpTransport({ url, timeout: 30000 });
Defensive patterns

Strategy: retry

Validate before calling

// size check before sending a bulky notification
const payload = JSON.stringify({ jsonrpc: '2.0', method, params });
if (payload.length > 1_000_000) console.warn('Notification payload large; raise timeout or split');

Type guard

function isNotifyTimeout(e: unknown): e is MCPTransportError {
  return e instanceof MCPTransportError && e.failure === 'timeout' && /Notify timeout after/.test(e.message);
}

Try / catch

try {
  await transport.notify(method, params);
} catch (e) {
  if (isNotifyTimeout(e)) {
    // delivery unknown — never blind-retry; verify server-side state first
    logger.warn('MCP notify timed out', { traceId: e.traceId });
  } else throw e;
}

Prevention

When it happens

Trigger: Server slow to accept the POST (overloaded, GC pause, blocked handler); configured timeout lower than server processing latency; network stall between client and server; response SSE piggyback stream kept open longer than the timeout.

Common situations: Large notification payloads over slow links; MCP server handling a long-running tool that blocks its event loop; timeout config tuned for requests applied to a heavily loaded server; proxy queuing delays.

Understand the failure class

Related errors


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