NousResearch/hermes-agent · error · GatewayReauthRequiredError

Your remote gateway session has expired. Open Settings -> Ga

Error message

Your remote gateway session has expired. Open Settings -> Gateway and click "Sign in" again.

What it means

A GatewayReauthRequiredError thrown by resolveGatewayWsUrl when minting a fresh OAuth WebSocket ticket reports needsOauthLogin — the remote gateway session/OAuth grant has expired and no ticket can be issued until the user re-authenticates. The error message directs the user to Settings -> Gateway -> Sign in; the underlying mint failure is chained as cause.

Source

Thrown at apps/shared/src/websocket-url.ts:60

  if (conn.authMode === 'oauth') {
    if (!mint) {
      throw new Error('This Desktop build cannot refresh OAuth WebSocket tickets. Update Hermes Desktop and try again.')
    }

    try {
      const result = await mint(profile)

      if (typeof result === 'string') {
        return result
      }

      if (result.ok) {
        return result.wsUrl
      }

      if (result.needsOauthLogin) {
        throw new GatewayReauthRequiredError(
          'Your remote gateway session has expired. Open Settings -> Gateway and click "Sign in" again.',
          { cause: new Error(result.error) }
        )
      }

      throw new Error(result.error || 'Could not refresh the remote gateway WebSocket ticket.')
    } catch (error) {
      if (isGatewayReauthRequired(error)) {
        throw error instanceof GatewayReauthRequiredError
          ? error
          : new GatewayReauthRequiredError(
              'Your remote gateway session has expired. Open Settings -> Gateway and click "Sign in" again.',
              { cause: error }
            )
      }

      throw error
    }

View on GitHub (pinned to c896c09c42)

Solutions

  1. Follow the prompt: open Settings -> Gateway and click 'Sign in' to redo the OAuth flow.
  2. If it recurs quickly, check system clock accuracy and the gateway's session/token TTL settings.
  3. Handle this typed error in UI to route the user to re-auth rather than showing a generic connection failure.

Example fix

// before
catch (e) { showGenericError(e) }

// after
catch (e) {
  if (isGatewayReauthRequired(e)) openGatewaySettingsForReauth()
  else showGenericError(e)
}
Defensive patterns

Strategy: try-catch

Type guard

function isGatewayReauthRequiredError(e: unknown): e is GatewayReauthRequiredError {
  return e instanceof GatewayReauthRequiredError
    || (typeof e === 'object' && e !== null && (e as { needsOauthLogin?: unknown }).needsOauthLogin === true)
}

Try / catch

try {
  const url = await resolveGatewayWsUrl(deps, conn)
} catch (e) {
  if (isGatewayReauthRequiredError(e)) {
    routeToGatewaySignIn() // Settings -> Gateway -> Sign in
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Long-lived Desktop connection to a remote (or Hermes Cloud) gateway whose OAuth access/refresh token expired or was revoked; the next reconnect attempts to mint a WS ticket, the backend answers needsOauthLogin, and this typed error is raised.

Common situations: Returning to the app after days idle, refresh token revoked server-side, clock skew invalidating tokens, or gateway-side session purge.

Related errors


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