CherryHQ/cherry-studio · error · Error

Failed to get gateway URL: HTTP ${response.status} - ${error

Error message

Failed to get gateway URL: HTTP ${response.status} - ${errorText}

What it means

Thrown by DiscordAdapter.getGatewayUrl when the request to GET /gateway/bot returns a non-2xx status. The message includes the HTTP status and Discord's error body, so the exact cause is recoverable: 401 means the token is invalid, 429 means rate-limited, 5xx means Discord-side trouble. This call is the first step of startGateway, so a failure here aborts the gateway connection.

Source

Thrown at src/main/ai/channels/adapters/discord/DiscordAdapter.ts:280

      controller.dispose()
    }
    this.streamingControllers.clear()
    this.cleanup()
    this.log.info('Discord bot stopped')
  }

  // ─── Gateway Connection ───────────────────────────────────────

  private async getGatewayUrl(): Promise<string> {
    const response = await net.fetch(`${DISCORD_API_BASE}/gateway/bot`, {
      headers: {
        Authorization: `Bot ${this.botToken}`,
        'User-Agent': USER_AGENT
      }
    })
    if (!response.ok) {
      const errorText = await response.text().catch(() => '')
      throw new Error(`Failed to get gateway URL: HTTP ${response.status} - ${errorText}`)
    }
    const data = (await response.json()) as { url: string }
    return data.url
  }

  private async startGateway(): Promise<void> {
    if (this.isConnecting || this.shouldStop) return
    this.isConnecting = true

    try {
      this.cleanup()

      const gatewayUrl = this.resumeGatewayUrl ?? (await this.getGatewayUrl())
      const wsUrl = `${gatewayUrl}?v=10&encoding=json`
      this.log.info('Connecting to Discord gateway', { url: wsUrl })

      const ws = new WebSocket(wsUrl)
      this.ws = ws

View on GitHub (pinned to 726446b54c)

Solutions

  1. Read the status in the message: 401 → regenerate/fix the bot token; 429 → back off and retry with rate-limit handling; 5xx → retry after a short delay.
  2. Confirm the token has the bot scope and is not revoked in the Discord Developer Portal.
  3. Retry connect with exponential backoff for transient (429/5xx) failures.
  4. Check network/proxy/TLS interception that could be returning a non-Discord error body.

Example fix

// before: single-shot connect blows up on transient failures
await discordAdapter.connect()

// after: token check + backoff for transient gateway errors
if (!botToken) throw new Error('Discord bot token is required')
for (let attempt = 0; attempt < 3; attempt++) {
  try { await discordAdapter.connect(); break }
  catch (e) {
    if (!/HTTP (429|5\d\d)/.test(String(e)) || attempt === 2) throw e
    await sleep(2 ** attempt * 1000)
  }
}
Defensive patterns

Strategy: retry

Validate before calling

async function gatewayReachable(token: string): Promise<boolean> {
  const res = await net.fetch(`${DISCORD_API_BASE}/gateway/bot`, {
    headers: { Authorization: `Bot ${token}`, 'User-Agent': USER_AGENT }
  })
  return res.ok
}
if (!(await gatewayReachable(botToken))) {
  // surface a specific cause (token/rate-limit/Discord outage) before connect
}

Type guard

function isTransientGatewayError(e: unknown): boolean {
  return e instanceof Error && /HTTP (401|429|5\d\d)/.test(e.message)
}

Try / catch

for (let attempt = 0; attempt < 3; attempt++) {
  try {
    await discordAdapter.connect(); break
  } catch (e) {
    const transient = e instanceof Error && /HTTP (429|5\d\d)/.test(e.message)
    if (!transient || attempt === 2) throw e
    await new Promise((r) => setTimeout(r, 2 ** attempt * 1000))
  }
}

Prevention

When it happens

Trigger: performConnect -> startGateway -> getGatewayUrl issues an authenticated request to DISCORD_API_BASE/gateway/bot and response.ok is false.

Common situations: Invalid/revoked bot token (401); missing the bot scope; rate-limited by Discord (429); Discord API outage (5xx); network/proxy returning an error status; clock skew or TLS interception breaking the request.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/5f85b35df9f3c6e2. Report an issue: GitHub.