NousResearch/hermes-agent · error

gateway not connected: ${method}

Error message

gateway not connected: ${method}

What it means

Thrown by GatewayClient.ensureAttachedWebSocket after it attempted (re)connection: attachUrl exists, start() was called if needed, the CONNECTING promise was awaited, but the WebSocket still is not in OPEN state — the connection attempt failed, closed immediately, or is stuck. The method name is included to identify which RPC was blocked.

Source

Thrown at ui-tui/src/gatewayClient.ts:686

  private async ensureAttachedWebSocket(method: string): Promise<WebSocket> {
    if (!this.attachUrl) {
      throw new Error('gateway not running')
    }

    if (!this.ws || this.ws.readyState === WS_CLOSED || this.ws.readyState === WS_CLOSING) {
      this.start()
    }

    if (this.ws?.readyState === WS_CONNECTING) {
      try {
        await this.wsConnectPromise
      } catch (err) {
        throw err instanceof Error ? err : new Error(String(err))
      }
    }

    if (!this.ws || this.ws.readyState !== WS_OPEN) {
      throw new Error(`gateway not connected: ${method}`)
    }

    return this.ws
  }

  private requestOverWebSocket<T = unknown>(method: string, params: Record<string, unknown> = {}): Promise<T> {
    return this.ensureAttachedWebSocket(method).then(
      ws =>
        new Promise<T>((resolve, reject) => {
          const id = `r${++this.reqId}`
          const timeout = setTimeout(this.onTimeout, REQUEST_TIMEOUT_MS, id)

          timeout.unref?.()
          this.pending.set(id, {
            id,
            method,
            reject,
            resolve: v => resolve(v as T),

View on GitHub (pinned to c896c09c42)

Solutions

  1. Verify the gateway is actually running and listening on the configured URL/port.
  2. Check gateway logs for handshake/auth failures; fix credentials if the socket is closed on auth.
  3. Retry after the gateway reports ready; add backoff/retry around RPCs issued during startup.
  4. Confirm no proxy in between strips WebSocket upgrades (wss/WS upgrade headers).
Defensive patterns

Strategy: retry

Validate before calling

function wsOpen(client: GatewayClient): boolean {
  return client.ws?.readyState === WebSocket.OPEN
}

// issue RPCs only when wsOpen(client) is true, or after the ready event

Type guard

function isWsOpen(ws: WebSocket | undefined): ws is WebSocket {
  return ws !== undefined && ws.readyState === WebSocket.OPEN
}

Try / catch

try {
  await client.rpc(method, params)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('gateway not connected')) {
    await backoff(500)
    return client.rpc(method, params) // single retry after reconnect
  }
  throw e
}

Prevention

When it happens

Trigger: Any gateway.rpc(...) while the WebSocket handshake fails: backend not listening on the port/URL, auth rejection closing the socket, network unreachable, or the socket closing between the connect-await and the state check.

Common situations: Gateway process crashed or still booting when the TUI connects, wrong port/URL in config, firewall/proxy blocking WS upgrade, or token auth failing so the server closes the connection instantly.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/eee3a62ea3e0261d. Report an issue: GitHub.