Remora/Remora.Discord

[Bug]: Conditions are evaluated before having a CommandContext

MazeXP opened this issue · 9 comments

Description

Currently any condition by Remora.Discord itself is causing an InvalidOperationException.

Reported by Patrick on Discord: https://discord.com/channels/789912892426027039/789913038920744960/1051957624884695152

Steps to Reproduce

Just add [RequireDiscordPermission] on any command.

Expected Behavior

The condition to be evaluated correctly.

Current Behavior

An InvalidOperationException is being thrown when the condition should actually be evaluated.

[20:23:26 WRN] Error in gateway event responder: No context has been set for this scope.
System.InvalidOperationException: No context has been set for this scope.
   at Remora.Discord.Commands.Extensions.ServiceCollectionExtensions.<>c.<AddDiscordCommands>b__1_1(IServiceProvider s)

Library / Runtime Information

Remora.Discord: 2022.50.0

Analysis

The cause for the exception is that during the evaluation of conditions in Remora.Commands, we do not have an ICommandContext in scope yet. [link]
We do only either have an IMessageContext or IInteractionContext, because ICommandContext will only be available after the command has been prepared. [link]

Possible solutions

  1. Do not use ICommandContext in conditions, but IOperationContext and match on IMessageContext and IInteractionContext.
  2. Change Remora.Commands to evaluate conditions in TryExecuteAsync instead of TryPrepareCommandAsync.

Thank you for the report! I'm going to switch them (and some of the parsers) over to IOperationContext instead, since they don't actually require command information to function.

The fix for this in 390ddbf

Has fixed the underlying exception, but now is defaulting the User ID to 0.

[19:20:11 INF] Sending HTTP request GET https://discord.com/api/v10/guilds/532257124131012640/members/0
info: System.Net.Http.HttpClient.RestHttpClient<RestError>.ClientHandler[101]
      Received HTTP response headers after 168.4273ms - 404

Likely here:

var userID = _context switch
{
IInteractionContext ix => ix.Interaction.User.IsDefined(out var user) ? user.ID : default,
IMessageContext tx => tx.Message.Author.IsDefined(out var author) ? author.ID : default,
_ => throw new NotSupportedException()
};

I'm running as a member within a guild. Member => User.

Is this with an interaction or a text command?

Slash command, so interaction I suppose

Gotcha; one moment.

Should be fixed now - I added a couple of helper extensions for extracting user/channel/guild IDs when you don't really care about the context type.

Haha; I did the same a day ago.

Confirmed fix in .52