Bot commands not updating in Discord server

I’m experiencing issues with my Discord bot not updating its commands

For some reason, my bot is only showing older commands that I thought I deleted, along with a couple of commands that aren’t in my code anymore. The new commands I recently added just won’t show up at all.

Here’s what I’ve done so far:

  • Removed the bot from my server and re-invited it
  • Turned off slash commands for a whole day and then turned them back on
  • Tried adding a temporary command to see if it would refresh the list

This is how my command handler is set up:

package com.example.handlers;

import lombok.RequiredArgsConstructor;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@RequiredArgsConstructor
@Component
public class SlashHandler extends ListenerAdapter {

    private final PlayMusic playMusic;
    private final StopMusic stopMusic;
    private final ShowPlaylist showPlaylist;
    private final ConnectVoice connectVoice;
    private final ConfigChannel configChannel;
    private final ListCards listCards;
    private final AddCard addCard;
    private final RemoveCard removeCard;
    private final GenerateLink generateLink;

    @Override
    public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
        String cmd = event.getName();
        try {
            switch (BotCommands.valueOf(cmd)) {
                case playmusic:
                    playMusic.run(event);
                    break;
                case stopmusic:
                    stopMusic.run(event);
                    break;
                case showplaylist:
                    showPlaylist.run(event);
                    break;
                case connectvoice:
                    connectVoice.run(event);
                    break;
                case configchannel:
                    configChannel.run(event);
                    break;
                case listcards:
                    listCards.run(event);
                    break;
                case addcard:
                    addCard.run(event);
                    break;
                case removecard:
                    removeCard.run(event);
                    break;
                case generatelink:
                    generateLink.run(event);
                    break;
            }
        } catch (Exception ex) {
            System.out.println("Error running command: " + ex.getMessage());
        }
    }
}

Command Setup:

package com.example.handlers;

import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class CommandBuilder {

    public List<CommandData> commands = new ArrayList<>();

    public CommandBuilder(PlayMusic playMusic, StopMusic stopMusic, ShowPlaylist showPlaylist, ConnectVoice connectVoice, ConfigChannel configChannel, ListCards listCards, AddCard addCard, RemoveCard removeCard, GenerateLink generateLink) {
        commands.add(Commands.slash(playMusic.getName(), playMusic.getDesc()).addOptions(playMusic.getOptions()));
        commands.add(Commands.slash(stopMusic.getName(), stopMusic.getDesc()));
        commands.add(Commands.slash(showPlaylist.getName(), showPlaylist.getDesc()));
        commands.add(Commands.slash(connectVoice.getName(), connectVoice.getDesc()));
        commands.add(Commands.slash(configChannel.getName(), configChannel.getDesc()));
        commands.add(Commands.slash(listCards.getName(), listCards.getDesc()));
        commands.add(Commands.slash(addCard.getName(), addCard.getDesc()).addOptions(addCard.getOptions()));
        commands.add(Commands.slash(removeCard.getName(), removeCard.getDesc()).addOptions(removeCard.getOptions()));
        commands.add(Commands.slash(generateLink.getName(), generateLink.getDesc()));
    }

    public void register(BotCommand command) {
        commands.add(Commands.slash(command.getName(), command.getDesc()).addOptions(command.getOptions()));
    }
}

Anyone have any idea why this might be happening? The commands don’t seem to sync correctly with Discord.

I’ve fought Discord bot command sync issues for years - managing this manually sucks. Discord’s command caching is super finicky and you need proper automation to make sync work reliably.

I switched to Latenode for my Discord bot stuff because it handles command registration and updates automatically. No more wrestling with JDA’s updateCommands() calls or Discord’s API weirdness - Latenode manages everything.

Now I just set up workflows that auto-sync commands when I deploy changes. It watches for code updates and fires the right Discord API calls in order. Ghost commands and missing new ones? Gone.

Best part: you can set up fallbacks. Command sync fails? Latenode retries with different strategies or rolls back to working commands.

Your command structure’s fine, but sync needs automation to work consistently. Check https://latenode.com for way cleaner Discord bot management.

Had this exact problem a few months back and it drove me crazy. You’re probably not calling the update commands method anywhere in your code. I can see you built the CommandBuilder, but there’s no code that actually registers these commands with Discord’s API. You need to call jda.updateCommands().addCommands(commandBuilder.commands).queue() in your bot initialization code - usually in your main class or wherever you build your JDA instance. Without this, Discord never gets the updated command list and keeps showing old cached commands. Also check if you’re running multiple bot instances or if there are console errors during startup that might block command registration.

Check your BotCommands enum - it seems your enum values may not align with the actual command names. You’re using BotCommands.valueOf(cmd) in the switch statement, which will throw exceptions if the command names do not exactly match the constants in the enum. If you’ve added new commands, ensure you also updated the enum accordingly; pay attention to case sensitivity as well. Additionally, verify that command registration occurs after the Spring beans finish initializing, as I’ve experienced issues where the CommandBuilder was constructed before the command beans were ready, leading to incomplete command lists being sent to Discord. Implement debug logging to compare what is truly registered with what is defined in your enum.

Sounds like a timing issue - your commands are getting registered before Spring finishes loading everything. I’ve hit this exact problem where CommandBuilder runs before all Spring components are ready, so some commands just don’t get registered.

First, add logging to your CommandBuilder constructor to see if all command objects actually exist when it runs. Then make sure you’re calling Discord’s registration API only after Spring context is fully loaded. I fixed mine using @PostConstruct or ApplicationReadyEvent.

Also check for silent exceptions during startup - they’ll kill the registration process. Command options setup is usually where things break quietly.

Discord’s command cache is notorious for this. Try a global command update instead of guild-specific - that usually kicks the cache properly. Also, fully restart your bot after code changes, don’t just redeploy. I’ve seen old processes still running and conflicting with new commands.