tinyhumansai/openhuman · error

Socket not connected

Error message

Socket not connected

What it means

transport.ts implements an MCP client transport over the app's Socket.IO connection (socketService). request() first checks this.socket?.connected and throws 'Socket not connected' when there is no live socket — before constructing the request promise. The MCP server proxying therefore depends entirely on the Socket.IO transport being established.

Source

Thrown at app/src/lib/mcp/transport.ts:119

  }

  off(event: string, handler: MCPEventHandler): void {
    if (!this.socket) return;
    const fullEvent = `${this.eventPrefix}${event}`;
    const handlersForEvent = this.eventHandlers.get(fullEvent);
    const wrappedHandler = handlersForEvent?.get(handler);

    if (wrappedHandler) {
      this.socket.off(fullEvent, wrappedHandler);
      handlersForEvent?.delete(handler);
    } else {
      this.socket.off(fullEvent, handler);
    }
  }

  async request(request: MCPRequest, timeoutMs = 30000): Promise<MCPResponse> {
    if (!this.socket?.connected) {
      throw new Error('Socket not connected');
    }

    mcpLog('Sending request', { id: request.id, method: request.method, timeoutMs });

    return new Promise<MCPResponse>((resolve, reject) => {
      const timeout = setTimeout(() => {
        this.requestHandlers.delete(request.id);
        mcpError('Request timeout', { id: request.id, method: request.method, timeoutMs });
        reject(new Error(`MCP request timeout after ${timeoutMs}ms`));
      }, timeoutMs);

      this.requestHandlers.set(request.id, (response: MCPResponse) => {
        clearTimeout(timeout);
        if (response.error) {
          mcpError('Request error', {
            id: request.id,
            method: request.method,
            error: sanitizeError(response.error),

View on GitHub (pinned to 7491200858)

Solutions

  1. Await socket connection (or subscribe to a connected event) before issuing MCP requests.
  2. Retry with backoff on 'Socket not connected' — Socket.IO auto-reconnects, so a short retry loop usually resolves it.
  3. Disable/grey out MCP-dependent UI while connectivity state is down, showing a reconnecting indicator.
  4. If the core was updated/restarted, wait for the app's socketService reconnect handshake to complete before re-opening MCP sessions.

Example fix

// before
const res = await transport.request(req);

// after
async function requestWithRetry(req: MCPRequest, tries = 3) {
  for (let i = 0; i < tries; i++) {
    try { return await transport.request(req); }
    catch (e) {
      if (String(e.message).includes('Socket not connected') && i < tries - 1) {
        await waitForSocketConnected(); continue;
      }
      throw e;
    }
  }
}
Defensive patterns

Strategy: retry

Validate before calling

if (!transport.socket?.connected) {
  await waitForSocketConnected(5000); // app-specific helper
}
const res = await transport.request(req);

Type guard

function isSocketDisconnectedError(e: unknown): boolean {
  return e instanceof Error && e.message === 'Socket not connected';
}

Try / catch

for (let i = 0; i < 3; i++) {
  try {
    return await transport.request(req);
  } catch (e) {
    if (!isSocketDisconnectedError(e) || i === 2) throw e;
    await waitForSocketConnected(2000);
  }
}

Prevention

When it happens

Trigger: Issuing any MCP request (tools/list, tools/call, prompts/get) while socket is null (never connected), disconnected (server restart, network drop, sleep/resume), or in a reconnect backoff window. Also when the MCP UI mounts and fires requests before the socket provider finishes connecting.

Common situations: App resumed from sleep with the socket still reconnecting; core restarted (update applied) invalidating the socket; dev hot-reload resetting socket state; offline/captive-network environments; race at startup where MCP panels query immediately.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/fb6fba88e3af9e54. Report an issue: GitHub.