NousResearch/hermes-agent · error

gateway not running

Error message

gateway not running

What it means

Thrown by GatewayClient.ensureAttachedWebSocket when an RPC is attempted but this.attachUrl is unset — the client has no gateway WebSocket URL to attach to, meaning the gateway process/connection was never started (or was fully torn down). Unlike a connect failure, this is the 'nothing to connect to' case.

Source

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

        this.emit('event', ev)
      }

      if (this.pendingExit !== undefined) {
        const code = this.pendingExit

        this.pendingExit = undefined
        this.emit('exit', code)
      }
    })
  }

  getLogTail(limit = 20): string {
    return this.logs.tail(Math.max(1, limit)).join('\n')
  }

  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}`)
    }

View on GitHub (pinned to c896c09c42)

Solutions

  1. Ensure the gateway is started/connected (await the client's ready/connect event) before issuing RPCs.
  2. If using an external gateway, verify its URL is configured so attachUrl gets set at construction.
  3. Gate UI actions that need the gateway on connection state; re-establish after an exit event.

Example fix

// before
const res = await client.rpc('session.list')

// after
await client.whenReady?.() // or start()/connect first
const res = await client.rpc('session.list')
Defensive patterns

Strategy: type-guard

Validate before calling

function hasAttachUrl(client: GatewayClient): boolean {
  return Boolean((client as unknown as { attachUrl?: string }).attachUrl)
}

Type guard

function isAttached(client: GatewayClient): boolean {
  return client.attachUrl !== undefined && client.ws?.readyState === WebSocket.OPEN
}

Try / catch

try {
  await client.rpc('session.list')
} catch (e) {
  if (e instanceof Error && e.message === 'gateway not running') {
    await client.start(); await ready
    return client.rpc('session.list')
  }
  throw e
}

Prevention

When it happens

Trigger: Calling gateway.rpc(...) / requestOverWebSocket before start() established attachUrl, or after stop()/exit cleared it; also when the TUI launches without spawning/connecting to a gateway (misconfigured remote mode).

Common situations: TUI startup race where a component issues an RPC before gateway ready, using --no-spawn/remote flags without a gateway URL configured, or issuing requests after the gateway exited.

Related errors


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