Skip to content

fix(events): prevent duplicate slash command and button execution#127

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-correctness-bugs-258b
Draft

fix(events): prevent duplicate slash command and button execution#127
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-correctness-bugs-258b

Conversation

@cursor

@cursor cursor Bot commented Jun 15, 2026

Copy link
Copy Markdown

Bug and impact

Duplicate interaction execution — After the events-handler regression fix (c430893), slash commands and buttons were handled by two independent interactionCreate listeners that ran in parallel:

  1. src/events/validations/* validators (calling command.run() / button.run())
  2. src/events/Guild/interactionCreate.js and components.js (also calling run())

Because Discord.js does not await async listeners, both paths executed concurrently before interaction.replied was set. This caused:

  • Economy corruption/beg, /deposit, /withdraw applied balance changes twice
  • Duplicate DB writes — e.g. /afk set could create two records
  • Double dev /eval — arbitrary code executed twice for authorized developers
  • Double button side effects — ticket/setup flows could run DB writes twice

Moderation crash/ban and /kick dereferenced member.bannable / member.kickable when getMember() returned null (user not in guild), causing an uncaught TypeError.

Root cause

Validators were left as full executors while Guild handlers were restored as separate per-module listeners. Three interactionCreate listeners fired in parallel for every interaction.

Fix

  • Consolidate all interactionCreate handlers into one sequential listener in src/handlers/events.js (validators first, then command router, then components)
  • Change validators to gate only — remove await *.run() calls; Guild handlers own execution
  • Make components.js async and await component handlers
  • Add null-member guards to /ban and /kick (matching /timeout)

Validation

  • npm test — 40/40 passing
  • New regression tests:
    • tests/events-handler-shape.test.js — single consolidated listener + validators don't execute
    • tests/moderation-member-null-guard.test.js — ban/kick null guard ordering
Open in Web View Automation 

Consolidate all interactionCreate handlers (validators, command router,
components) into one sequential listener. Validators now gate only;
Guild handlers own execution. Fixes economy corruption from double
/beg, /deposit, etc. and double button side effects.

Also guard null getMember() in /ban and /kick before bannable/kickable
checks to avoid crashes when targeting non-members.

Co-authored-by: zVapor_ <contact@zvapor.xyz>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant