fix(discord): cap slash commands at Discord's 100-command limit - #46078
Conversation
Discord enforces a hard cap of 100 global application commands per app.
The adapter registers ~27 native commands plus every gateway-available
entry in COMMAND_REGISTRY plus all plugin commands plus the consolidated
/skill group. On a loaded install (many plugins/quick commands) the
desired set exceeds 100, so tree.sync() / _safe_sync_slash_commands()
hits error 30032 ("Maximum number of application commands reached") and
Discord rejects the ENTIRE batch — silently breaking every slash command,
not just the overflow.
Cap registration at the 100-command limit: native commands (registered
first, highest priority) and the /skill group are always kept; lower-
priority auto-registered COMMAND_REGISTRY and plugin commands are added
only until the cap is reached, with a single concise warning telling the
user how to surface the rest. Since both sync paths read from
tree.get_commands(), bounding the tree fixes the root cause for both.
Registers 200 plugin commands on top of the native + COMMAND_REGISTRY set
and asserts the tree never exceeds Discord's 100-command limit, that native
high-priority commands survive the cap, and that overflow is actually
dropped. Regression guard for the recurring error 30032
("Maximum number of application commands reached") sync failures.
|
Verification: Reviewed the diff — the 100-command cap implementation is clean.
One observation: the |
kshitijk4poor
left a comment
There was a problem hiding this comment.
Reviewed end-to-end and verified every claim against the current code.
Root cause confirmed. On current main, _register_slash_commands registers 27 native commands + 50 gateway-available COMMAND_REGISTRY entries before a single plugin or /skill — that's already 77. Any install with ~24+ plugin commands pushes the desired set past 100, and Discord then rejects the entire tree.sync() batch with error 30032, silently breaking every slash command (not just the overflow). This matches the reported symptom exactly.
Fix is correct and minimal. Capping at registration time bounds both sync paths, since tree.sync() and _safe_sync_slash_commands() both serialize whatever's in tree.get_commands(). Native commands and the consolidated /skill group are reserved and always survive; lower-priority auto-registered + plugin commands fill the remaining slots. I confirmed the tree never exceeds 100 and native commands (/status, /stop, /new, /model, /help) are preserved.
Verified locally:
tests/gateway/test_discord_slash_commands.py— 34/34 pass;test_discord_connect.py(18) andtest_discord_slash_auth.py(32) unaffected.- The new test is a genuine regression guard — it fails against the unfixed adapter and passes against the fix.
- This is also the only fix targeting the current path:
gateway/platforms/discord.pyhas moved toplugins/platforms/discord/adapter.py, so the older PRs in this area no longer apply.
One cosmetic note (non-blocking): the /skill slot is reserved unconditionally, so on an install with zero skills the tree maxes at 99 and one extra command that could have fit is dropped. Harmless — the safety invariant (never exceed 100) holds in all cases. Not worth blocking on.
Approving and merging. Thanks for the clean, well-scoped fix and the precise root-cause writeup. 🙏
…ommand-100-cap fix(discord): cap slash commands at Discord's 100-command limit
…ommand-100-cap fix(discord): cap slash commands at Discord's 100-command limit
…ommand-100-cap fix(discord): cap slash commands at Discord's 100-command limit
…ommand-100-cap fix(discord): cap slash commands at Discord's 100-command limit
…ommand-100-cap fix(discord): cap slash commands at Discord's 100-command limit
…ommand-100-cap fix(discord): cap slash commands at Discord's 100-command limit
…ommand-100-cap fix(discord): cap slash commands at Discord's 100-command limit
What does this PR do?
Bounds the Discord adapter's desired slash-command set so it never exceeds Discord's hard cap of 100 global application commands, fixing recurring
400 Bad Request (error code: 30032): Maximum number of application commands reached (100)sync failures.The bug
_register_slash_commands()inplugins/platforms/discord/adapter.pyregisters:/new,/model,/stop, …)COMMAND_REGISTRY(~75CommandDef)_iter_plugin_command_entries())/skillgroupOn a loaded install (many plugins / quick commands) the desired set goes over 100. Discord then rejects the entire
tree.sync()/_safe_sync_slash_commands()batch with error 30032 — so every slash command silently breaks, not just the overflow. This shows up as a traceback on every gateway reconnect.This is the root cause that the existing open PRs don't cover:
gateway/platforms/discord.py, which has since moved toplugins/platforms/discord/adapter.py.The fix
Cap registration at the 100-command limit:
/skillgroup are always kept.COMMAND_REGISTRYand plugin commands are added only until the cap is reached.WARNINGtells the user how to surface the rest (disable unneeded commands / trim plugins).Because both sync paths read from
tree.get_commands(), bounding the tree fixes the root cause for both.Type of Change
Changes Made
plugins/platforms/discord/adapter.py: add_DISCORD_MAX_APP_COMMANDS = 100; cap theCOMMAND_REGISTRYand plugin auto-registration loops (reserving one slot for/skill); warn once when commands are dropped.tests/gateway/test_discord_slash_commands.py: register 200 plugin commands and assert the tree stays ≤ 100, native commands survive, and overflow is dropped.How to Test
All 34 tests pass;
tests/gateway/test_discord_connect.pyunaffected.