So the command works following. User selects category, and types query. Bot uses GraphQL client to search for stuff, sends message with 5 results. User now clicks button from 1-5 to select one object and bot edits the message. This works completely fine when using the command and buttons for the first time. But when trying second time whole process, the bot throws message NotFound in console:
[2023-12-25 02:56:21 +01:00] [104 /EventHandler] [Error] Event handler exception for event COMPONENT_INTERACTED thrown from System.Threading.Tasks.Task <SearchCommand>b__0(DSharpPlus.DiscordClient, DSharpPlus.EventArgs.ComponentInteractionCreateEventArgs) (defined in AnimeSharpBot.SearchModule+<>c__DisplayClass0_0)
DSharpPlus.Exceptions.NotFoundException: Not found: 404
at DSharpPlus.Net.DiscordApiClient.CreateInteractionResponseAsync(UInt64 interaction_id, String interaction_token, InteractionResponseType type, DiscordInteractionResponseBuilder builder)
at AnimeSharpBot.SearchModule.ButtonClick(DiscordClient sender, ComponentInteractionCreateEventArgs e, IEnumerable`1 animeDetails) in C:\Users\mrady\RiderProjects\AnimeSharpBot\SearchModule.cs:line 110
at AnimeSharpBot.SearchModule.<>c__DisplayClass0_0.<<SearchCommand>b__0>d.MoveNext() in C:\Users\mrady\RiderProjects\AnimeSharpBot\SearchModule.cs:line 44
--- End of stack trace from previous location ---
at DSharpPlus.AsyncEvents.AsyncEvent`2.<>c__DisplayClass7_0.<<InvokeAsync>b__0>d.MoveNext()
It's very confusing to me because the functionality works but getting that error for some reason. How can I fix it? Here is my code:
using System.Text;
using DSharpPlus;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using AniListNet;
using AniListNet.Objects;
using AniListNet.Parameters;
using DSharpPlus.EventArgs;
namespace AnimeSharpBot;
public class SearchModule : ApplicationCommandModule
{
[SlashCommand("search", "Search for anime, manga, staff, character, or studio")]
public async Task SearchCommand(InteractionContext ctx,
[Option("category", "Category to search for")]
[Choice("Anime", "anime")]
[Choice("Manga", "manga")]
[Choice("Staff", "staff")]
[Choice("Character", "character")]
[Choice("Studio", "studio")]
string category,
[Option("query", "Search query")]
string query)
{
var (resultMessage, animeDetails) = await SearchAsync(category, query);
var row = new DiscordComponent[]
{
new DiscordButtonComponent(ButtonStyle.Primary, "option_1", "1"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_2", "2"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_3", "3"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_4", "4"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_5", "5"),
};
var message = new DiscordMessageBuilder()
.WithContent(resultMessage)
.AddComponents(row)
.SendAsync(ctx.Channel);
var client = ctx.Client;
client.ComponentInteractionCreated += async (sender, e) =>
await ButtonClick(sender, e, animeDetails);
}
private async Task<(string ResultMessage, IEnumerable<Media> AnimeDetails)> SearchAsync(string category, string query)
{
var resultMessage = new StringBuilder();
var client = new AniClient();
IEnumerable<Media> animeDetails = null;
if (category.Equals("anime", StringComparison.OrdinalIgnoreCase))
{
var results = await client.SearchMediaAsync(new SearchMediaFilter
{
Query = query,
Type = MediaType.Anime,
Sort = MediaSort.Popularity,
Format = new Dictionary<MediaFormat, bool>
{
{ MediaFormat.TV, true },
{ MediaFormat.Movie, true },
{ MediaFormat.TVShort, true }
}
});
for (int i = 0; i < Math.Min(results.Data.Length, 5); i++)
{
var animeTitle = results.Data[i].Title.EnglishTitle;
resultMessage.AppendLine($"Result {i + 1}: {animeTitle}");
}
animeDetails = results.Data;
}
else if (category.Equals("manga", StringComparison.OrdinalIgnoreCase))
{
}
else if (category.Equals("staff", StringComparison.OrdinalIgnoreCase))
{
}
else if (category.Equals("character", StringComparison.OrdinalIgnoreCase))
{
}
else if (category.Equals("studio", StringComparison.OrdinalIgnoreCase))
{
}
else
{
return ("Please choose a valid category (anime, manga, staff, character, studio).", null);
}
return (resultMessage.ToString(), animeDetails);
}
private async Task ButtonClick(DiscordClient sender, ComponentInteractionCreateEventArgs e, IEnumerable<Media> animeDetails)
{
int selectedOption = int.Parse(e.Id.Substring("option_".Length));
var selectedAnime = animeDetails.ElementAtOrDefault(selectedOption - 1);
if (selectedAnime != null)
{
await e.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage,
new DiscordInteractionResponseBuilder().WithContent($"You selected option {selectedOption}! Here are the details:\n{selectedAnime.Title.EnglishTitle} (ID: {selectedAnime.Id})\n{selectedAnime.Description}"));
}
}
}
You can make any suggestion apart from fixing it if you'd like if something is really bothering.
The source of your error is found in this code here, I commented in the place where it is caused and the source of the issue
The issue occurs when you call the
ComponentInteractionCreatedevent by getting theComponentInteractionCreateEventArgsmore than 3 seconds after the firstComponentInteractionCreatedevent is fired. You can fix this by usingDeferredMessageUpdateinstead ofUpdateMessageto fire follow up messages. DeferredMessageUpdate API info can be found here and DiscordFollowUpMessageBuilder can be found hereYou can find the example that discusses this from DSharpPlus directly here
Another way to fix this would be to delete the original message the bot sent and resend the same message with the same content and buttons when an interaction occurs but that's a little more jank and for use cases where the API doesn't actually agree with what you're doing.