{"record":{"id":"a6da1ca99e1ab79a","repo":"can1357/oh-my-pi","slug":"transport-not-connected","errorCode":null,"errorMessage":"Transport not connected","messagePattern":"Transport not connected","errorType":"exception","errorClass":"MCPTransportError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/mcp/transports/http.ts","lineNumber":425,"sourceCode":"\t\t\tif (!(error instanceof SSEResumeError) && this.onAuthError && (status === 401 || status === 403)) {\n\t\t\t\tconst newHeaders = await this.onAuthError();\n\t\t\t\tif (newHeaders) {\n\t\t\t\t\t// Persist refreshed headers so subsequent requests use them directly\n\t\t\t\t\tthis.config = { ...this.config, headers: newHeaders };\n\t\t\t\t\treturn this.#executeRequest<T>(method, params, options);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync #executeRequest<T>(\n\t\tmethod: string,\n\t\tparams: Record<string, unknown> | undefined,\n\t\toptions: MCPRequestOptions | undefined,\n\t): Promise<T> {\n\t\tif (!this.#connected) {\n\t\t\tthrow new MCPTransportError({\n\t\t\t\ttransport: \"http\",\n\t\t\t\tstage: \"connect\",\n\t\t\t\tfailure: \"closed\",\n\t\t\t\tmessage: \"Transport not connected\",\n\t\t\t\tretryable: true,\n\t\t\t});\n\t\t}\n\n\t\tconst id = this.#requestIds.next(this.config.requestIdFormat);\n\t\tconst body = {\n\t\t\tjsonrpc: \"2.0\" as const,\n\t\t\tid,\n\t\t\tmethod,\n\t\t\tparams: params ?? {},\n\t\t};\n\n\t\tconst generated: Record<string, string> = {\n\t\t\t\"Content-Type\": \"application/json\",","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/mcp/transports/http.ts#L407-L443","documentation":"request() was called on the HTTP MCP transport before connect() completed or after the transport was disconnected. The transport guards every JSON-RPC execution with a #connected flag and throws this MCPTransportError (stage: connect, failure: closed, retryable: true).","triggerScenarios":"Calling transport.request(...) without a prior successful connect(); after close(); after the SSE listener detected a fatal stream end and fired onClose while requests are still in flight.","commonSituations":"Application code racing a slow connect (calling tools before initialization resolves); reusing a transport singleton after teardown; a reconnect cycle dropping requests submitted in the gap.","solutions":["Await transport.connect() before issuing any request() calls","Check the connected state (or listen for onClose) before enqueueing requests; queue or re-create the transport when disconnected","Retry with a fresh connect — the error is marked retryable","Fix lifecycle races: ensure teardown (close) completes before dropping references, and don't share one transport across async contexts without a ready-gate"],"exampleFix":"// before\ntransport.request(\"tools/call\", { name: \"search\" }); // may throw if not connected\n// after\nif (!transport.isConnected()) await transport.connect();\nawait transport.request(\"tools/call\", { name: \"search\" });","handlingStrategy":"validation","validationCode":"// Gate all requests on a ready promise established at setup:\nconst ready = transport.connect();\nasync function safeRequest<T>(m: string, p?: Record<string, unknown>) {\n  await ready;\n  return transport.request<T>(m, p);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await transport.request(\"tools/list\");\n} catch (err) {\n  if (err instanceof MCPTransportError && err.failure === \"closed\" && err.stage === \"connect\") {\n    await transport.connect();\n    await transport.request(\"tools/list\");\n  } else throw err;\n}","preventionTips":["Always await connect() before the first request","Subscribe to onClose and pause/queue requests until reconnected","Serialize lifecycle: no requests during close/reconnect windows","Check connectivity state in request wrapper helpers"],"tags":["mcp","lifecycle","transport","state"],"backgroundTag":"transport-not-connected","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}