openclaw - ✅(Solved) Fix Discord: channels.discord.voice.enabled=false still subscribes to GuildVoiceStates intent, causing sustained gateway CPU spin [1 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#73709Fetched 2026-04-29 06:16:07
View on GitHub
Comments
2
Participants
3
Timeline
5
Reactions
0
Timeline (top)
commented ×2cross-referenced ×2closed ×1

Setting channels.discord.voice.enabled=false in OpenClaw config does not remove the GuildVoiceStates gateway intent from the embedded Discord provider. The intent is hardcoded unconditionally in resolveDiscordGatewayIntents(), causing the gateway process to spin at ~100% CPU on Linux (confirmed on Hetzner CPX31, 4 vCPU AMD) and ~20-33% on macOS (Apple Silicon Mac Studio) at idle with no active tasks.

Root Cause

In dist/extensions/discord/provider-Cj0uV2UO.js, resolveDiscordGatewayIntents() unconditionally includes GuildVoiceStates in the intent bitmask:

// Current (broken)
function resolveDiscordGatewayIntents(intentsConfig) {
  let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | 
    GatewayIntents.MessageContent | GatewayIntents.DirectMessages | 
    GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions | 
    GatewayIntents.GuildVoiceStates; // <-- always included
  ...
}

Fix Action

Fix / Workaround

Config used alongside the patch:

{
  "channels": {
    "discord": {
      "enabled": true,
      "voice": {
        "enabled": false
      }
    }
  }
}
  • Linux: Hetzner CPX31, 4 vCPU AMD, 8 GB RAM — gateway pinned at ~100% CPU at idle
  • macOS: Apple Silicon Mac Studio — gateway at ~20-33% CPU at idle
  • Both resolved by the local patch above

PR fix notes

PR #73714: fix(discord): gate GuildVoiceStates intent on voice.enabled (#73709)

Description (problem / solution / changelog)

What

Fixes #73709. resolveDiscordGatewayIntents unconditionally OR'd GatewayIntents.GuildVoiceStates into the requested intent bitmask regardless of channels.discord.voice.enabled. The result: a sustained ~100% CPU spin in the gateway process on Linux (Hetzner CPX31, 4 vCPU AMD confirmed) and ~20-33% on macOS (Apple Silicon Mac Studio) at idle, because the Discord gateway kept dispatching voice-state events that nothing consumed when voice was meant to be off.

Fix

Pass the existing discordConfig.voice config through to the intent resolver and gate GuildVoiceStates on voice.enabled !== false:

if (voiceConfig?.enabled !== false) {
  intents |= carbonGateway.GatewayIntents.GuildVoiceStates;
}

Default behavior is unchanged — channels.discord.voice.enabled defaults to true, so the intent stays on for the common case. Operators who explicitly set voice.enabled: false (text-only Discord channel) now get a true text-only gateway connection without the CPU spin.

Why this shape rather than a new intents.voiceStates opt-in

The issuer's suggested local patch (in #73709) introduces a new channels.discord.intents.voiceStates opt-in field. That works, but:

  • Adding a new field requires a corresponding zod-schema.providers-core.ts strict-schema update.
  • It splits the user's intent across two config knobs (voice.enabled: false AND intents.voiceStates: false to actually go quiet).
  • Reusing the existing voice.enabled config the user already sets keeps the contract minimal and matches the user's actual mental model (turn off voice → no voice traffic).

Pre-implement audit

  1. Existing-helper check (vincentkoc #57341). Chose to reuse the existing voice.enabled config rather than introduce a new helper / config field. Saves a schema change. ✅
  2. Shared-helper caller check (steipete #60623). resolveDiscordGatewayIntents is exported from runtime-api.ts but only called from one in-tree site (gateway-plugin.ts:489); adding an optional second parameter is backward-compatible — external callers that pass only the first arg get the same default behavior (voice on). ✅
  3. Broader-fix rival scan (steipete #68270). Zero rival PRs reference #73709. ✅

Verified locally

npx oxlint extensions/discord/src/monitor/gateway-plugin.ts extensions/discord/src/monitor/gateway-intents.test.ts
# Found 0 warnings and 0 errors.

npx vitest run extensions/discord/src/monitor/gateway-intents.test.ts
# Tests  4 passed (4)

Tests cover:

  • Default (no args) → GuildVoiceStates set
  • voice.enabled: trueGuildVoiceStates set
  • voice.enabled: falseGuildVoiceStates cleared, base text intents preserved
  • Privileged intents (presence, guildMembers) layer independently of voice

lobster-biscuit: 73709-discord-voice-states-intent-gate

Sign-Off:

  • I have read and agree to the OpenClaw Contributor License Agreement.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/discord/src/monitor/gateway-intents.test.ts (added, +59/-0)
  • extensions/discord/src/monitor/gateway-plugin.ts (modified, +13/-3)

Code Example

// Current (broken)
function resolveDiscordGatewayIntents(intentsConfig) {
  let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | 
    GatewayIntents.MessageContent | GatewayIntents.DirectMessages | 
    GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions | 
    GatewayIntents.GuildVoiceStates; // <-- always included
  ...
}

---

// Fixed
function resolveDiscordGatewayIntents(intentsConfig) {
  let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | 
    GatewayIntents.MessageContent | GatewayIntents.DirectMessages | 
    GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions;
  if (intentsConfig?.voiceStates) intents |= GatewayIntents.GuildVoiceStates;
  if (intentsConfig?.presence) intents |= GatewayIntents.GuildPresences;
  if (intentsConfig?.guildMembers) intents |= GatewayIntents.GuildMembers;
  return intents;
}

---

{
  "channels": {
    "discord": {
      "enabled": true,
      "voice": {
        "enabled": false
      }
    }
  }
}
RAW_BUFFERClick to expand / collapse

Bug Report

Summary

Setting channels.discord.voice.enabled=false in OpenClaw config does not remove the GuildVoiceStates gateway intent from the embedded Discord provider. The intent is hardcoded unconditionally in resolveDiscordGatewayIntents(), causing the gateway process to spin at ~100% CPU on Linux (confirmed on Hetzner CPX31, 4 vCPU AMD) and ~20-33% on macOS (Apple Silicon Mac Studio) at idle with no active tasks.

Version

OpenClaw v2026.4.26

Steps to Reproduce

  1. Set channels.discord.voice.enabled=false in openclaw.json
  2. Start the gateway with embedded Discord enabled
  3. Monitor gateway process CPU: pidstat -p <pid> 1 10
  4. Observe sustained ~1 full CPU core usage with no active tasks

Expected Behavior

channels.discord.voice.enabled=false should produce a text-only Discord gateway connection with no voice-related intents requested.

Actual Behavior

The embedded Discord provider still requests GuildVoiceStates regardless of the voice config setting, causing sustained CPU spin in the gateway process.

Root Cause

In dist/extensions/discord/provider-Cj0uV2UO.js, resolveDiscordGatewayIntents() unconditionally includes GuildVoiceStates in the intent bitmask:

// Current (broken)
function resolveDiscordGatewayIntents(intentsConfig) {
  let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | 
    GatewayIntents.MessageContent | GatewayIntents.DirectMessages | 
    GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions | 
    GatewayIntents.GuildVoiceStates; // <-- always included
  ...
}

Local Fix

Make GuildVoiceStates opt-in via channels.discord.intents.voiceStates:

// Fixed
function resolveDiscordGatewayIntents(intentsConfig) {
  let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | 
    GatewayIntents.MessageContent | GatewayIntents.DirectMessages | 
    GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions;
  if (intentsConfig?.voiceStates) intents |= GatewayIntents.GuildVoiceStates;
  if (intentsConfig?.presence) intents |= GatewayIntents.GuildPresences;
  if (intentsConfig?.guildMembers) intents |= GatewayIntents.GuildMembers;
  return intents;
}

Config used alongside the patch:

{
  "channels": {
    "discord": {
      "enabled": true,
      "voice": {
        "enabled": false
      }
    }
  }
}

With this fix, channels.discord.intents.voiceStates must be explicitly set to true to subscribe to voice state events. Leaving it unset (default) produces a text-only gateway connection.

Related

  • #28587 — related CPU pressure from Discord SDK eager loading (distinct issue, same symptom area)

Environment

  • Linux: Hetzner CPX31, 4 vCPU AMD, 8 GB RAM — gateway pinned at ~100% CPU at idle
  • macOS: Apple Silicon Mac Studio — gateway at ~20-33% CPU at idle
  • Both resolved by the local patch above

extent analysis

TL;DR

To fix the issue, update the resolveDiscordGatewayIntents function to make GuildVoiceStates opt-in via the channels.discord.intents.voiceStates configuration.

Guidance

  • Verify that the channels.discord.voice.enabled setting is correctly applied by checking the openclaw.json configuration file.
  • Update the resolveDiscordGatewayIntents function to conditionally include GuildVoiceStates in the intent bitmask based on the channels.discord.intents.voiceStates configuration.
  • Test the updated configuration by setting channels.discord.intents.voiceStates to false and monitoring the gateway process CPU usage.
  • If issues persist, review related issues like #28587 for potential additional fixes.

Example

function resolveDiscordGatewayIntents(intentsConfig) {
  let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | 
    GatewayIntents.MessageContent | GatewayIntents.DirectMessages | 
    GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions;
  if (intentsConfig?.voiceStates) intents |= GatewayIntents.GuildVoiceStates;
  // ...
}

Notes

The provided local fix resolves the issue on both Linux and macOS environments, but it's essential to test the updated configuration thoroughly to ensure no regressions occur.

Recommendation

Apply the workaround by updating the resolveDiscordGatewayIntents function to make GuildVoiceStates opt-in, as this directly addresses the root cause of the issue and has been verified to resolve the problem on multiple environments.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Discord: channels.discord.voice.enabled=false still subscribes to GuildVoiceStates intent, causing sustained gateway CPU spin [1 pull requests, 2 comments, 3 participants]