C# Discord.NET 1.0 - Creating separate command modules issue

Issue with Command Recognition in Separate Module Class

I’m working on a Discord bot using Discord.NET 1.0 and C#. I can get commands to work when they’re in my main module, but when I try to create a separate class for organizing commands, the bot returns “Unknown command” errors.

Working Main Module

using Discord.Commands;
using System.Threading.Tasks;

namespace BotApp.Commands.Main
{
    public class MainCommands : ModuleBase
    {
        [Command("info")]
        [Summary("Shows bot information")]
        public async Task ShowInfo()
        {
            var app = await Context.Client.GetApplicationInfoAsync();
            await ReplyAsync($"Bot invite link: <https://discord.com/oauth2/authorize?client_id={app.Id}&scope=bot>");
        }

        [Command("exit")]
        [Summary("Makes the bot leave the server")]
        [RequireUserPermission(GuildPermission.Administrator)]
        public async Task ExitServer()
        {
            if (Context.Guild == null) 
            { 
                await ReplyAsync("This only works in servers."); 
                return; 
            }
            await ReplyAsync("Goodbye!");
            await Context.Guild.LeaveAsync();
        }
    }
}

Separate Module That Doesn’t Work

using Discord.Commands;
using System.Threading.Tasks;

namespace BotApp.Commands.Main
{
    class TextCommands : ModuleBase
    {
        [Command("repeat")]
        [Alias("copy")]
        [Summary("Repeats your message")]
        public async Task RepeatMessage([Remainder] string message)
        {
            await ReplyAsync(message);
        }
    }
}

The second class gives “Unknown command” when I try using the repeat command. Both classes are in the same namespace and follow the same pattern. What am I missing to make the separate module work properly?

Been there! You’re right about the access modifier, but also double-check you’re calling AddModulesAsync() right in your startup. People forget to await it or mess up the assembly reference. Add some debug logging to see if the module loads at startup - you’ll know fast if it’s registration or just the missing public keyword.

It’s your class access modifier. Your TextCommands class is just class TextCommands, which defaults to internal in C#. However, your MainCommands class is public class MainCommands. Discord.NET can’t register modules it can’t access. Change it to public class TextCommands : ModuleBase, and you should be good. I made this exact mistake when I started splitting commands into modules—it cost me hours of debugging before I noticed the missing public keyword.

Hit this exact issue last month. Yeah, it’s the access modifier like mikechen said, but check one more thing - make sure you’re loading the assembly with your TextCommands class when registering modules. With CommandService.AddModulesAsync(), it has to find all modules in the assembly. Sometimes new files don’t get included in the build properly. Fix the public modifier first, then do a clean rebuild. Also double-check your module registration code is scanning the right assembly - I’ve seen people accidentally register specific types instead of the whole assembly.