{"record":{"id":"728483b9e718b239","repo":"NousResearch/hermes-agent","slug":"hermes-gateway-unavailable-728483","errorCode":null,"errorMessage":"Hermes gateway unavailable","messagePattern":"Hermes gateway unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/src/store/wake-word.ts","lineNumber":145,"sourceCode":"  max_input_channels?: number\n  name?: string\n  selector?: number | string | null\n}\n\n/** Minimal requester shape — satisfied by both `useGatewayRequest`'s\n *  `requestGateway` and the `$gateway` instance wrapper below. */\nexport type WakeRequester = <T>(method: string, params?: Record<string, unknown>) => Promise<T>\n\n// First-use wake.start lazy-installs the detection engine (onnxruntime is a\n// large wheel) — that legitimately takes minutes. The default 30s WS timeout\n// fired mid-install, leaving a dead button that went blue on its own later.\nconst WAKE_START_TIMEOUT_MS = 180_000\n\nconst gatewayRequester: WakeRequester = async <T>(method: string, params: Record<string, unknown> = {}) => {\n  const gateway = $gateway.get()\n\n  if (!gateway) {\n    throw new Error('Hermes gateway unavailable')\n  }\n\n  return method === 'wake.start'\n    ? gateway.request<T>(method, params, WAKE_START_TIMEOUT_MS)\n    : gateway.request<T>(method, params)\n}\n\n// Friendly text for the gateway's wake refusal codes (mirrors the TUI's\n// START_REASON_TEXT). Unknown codes fall through raw so new server-side\n// codes stay visible instead of silently disappearing.\nconst REASON_TEXT: Record<string, string> = {\n  disabled: 'click to enable',\n  disabled_for_surface: 'scoped to another surface (config wake_word.surface)',\n  not_owner: 'another surface owns the listener',\n  owned: 'another surface owns the listener',\n  unavailable: 'unavailable'\n}\n","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/src/store/wake-word.ts#L127-L163","documentation":"Thrown by the wake-word store's gatewayRequester when it needs to send a wake.* RPC but $gateway.get() returns null — i.e. no gateway client instance has been created/connected yet. Wake-word start/stop/status all funnel through this requester, so any call before the gateway singleton exists fails fast with this message.","triggerScenarios":"Calling wake.start / wake.stop / wake.status through the wake-word UI or store before the desktop app established its gateway WebSocket connection, or after the gateway client was torn down on disconnect.","commonSituations":"App startup race (wake-word widget mounts before gateway connect completes), remote backend URL not reachable so $gateway stays null, or a session-end path that cleared the gateway atom.","solutions":["Wait for the gateway-ready signal ($gateway populated / connection established) before enabling or invoking wake-word controls.","Check the gateway connection in Settings -> Gateway; reconnect if the backend URL or auth is broken.","Bind the wake-word toggle's disabled state to gateway availability so the call cannot be made early.","If it persists, restart the app/backend — the gateway instance may have failed to initialize."],"exampleFix":"// before\nconst res = await wakeRequester('wake.start')\n\n// after\nif (!$gateway.get()) { throw new Error('Connect to the gateway first') }\nconst res = await wakeRequester('wake.start')","handlingStrategy":"type-guard","validationCode":"import { $gateway } from '.../store'\n\nif (!$gateway.get()) {\n  // disable wake-word UI instead of calling\n}","typeGuard":"function gatewayReady(): boolean {\n  return $gateway.get() !== null\n}","tryCatchPattern":"try {\n  await startWakeWord()\n} catch (e) {\n  if (e instanceof Error && e.message === 'Hermes gateway unavailable') awaitGatewayReadyThenRetry()\n  else throw e\n}","preventionTips":["Derive wake-word control disabled state from $gateway availability.","Subscribe to gateway connect/disconnect to re-evaluate wake-word state.","Never call wake.* from module init — wait for the ready event."],"tags":["desktop","wake-word","gateway","connection"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}