discord-jda / JDA

Java wrapper for the popular chat & VOIP service: Discord https://discord.com
Apache License 2.0
4.31k stars 737 forks source link

Random RestAction Error #1154

Closed alecfarmer closed 4 years ago

alecfarmer commented 4 years ago

I'm getting this error on one bot and not another. It's the exact same code on both and both are running the most recent version of JDA.

Code causing errors:

import com.jagrosh.jdautilities.commons.utils.FinderUtil;
import me.alec.atlas.Constants;
import me.alec.atlas.ICommand;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;

import java.util.List;
import java.util.concurrent.TimeUnit;

public class ClearCmd implements ICommand {
    @Override
    public void handle(List<String> args, GuildMessageReceivedEvent event) {
        TextChannel channel = event.getChannel();
        Member issuer = event.getMember();
        long owner = Constants.JARVIS_ID;
        List<Role> findRoleET = FinderUtil.findRoles("653022193219010580", event.getGuild());
        Role ETRole = findRoleET.get(0);
        List<Role> findRoleMT = FinderUtil.findRoles("653436803885563925", event.getGuild());
        Role MTRole = findRoleMT.get(0);
        List<Member> jarvis = FinderUtil.findMembers(String.valueOf(Constants.JARVIS_ID), event.getGuild());
        Member jarvisU = jarvis.get(0);
        assert issuer != null;

        EmbedBuilder noPerm = new EmbedBuilder();
        noPerm.setColor(Constants.ACOLOR);
        noPerm.setDescription("You don't have permission to use this command");

        if(args.isEmpty()) {
            channel.sendMessage(new EmbedBuilder().setColor(Constants.ACOLOR)
                    .setDescription("Too few arguments\n\n" +
                            "Usage:\n" +
                            "`"+ Constants.PREFIX + getInvoke() + " <amount>`")
                    .build()).queueAfter(10, TimeUnit.SECONDS);
            return;
        }
        else if(!(issuer.getIdLong() == owner)) {
            channel.sendMessage(noPerm.build()).queue(m -> m.delete().queueAfter(10, TimeUnit.SECONDS));
            //event.getMessage().delete().queue();
            return;
        }
        else if(!issuer.getRoles().contains(ETRole)) {
            channel.sendMessage(noPerm.build()).queue(m -> m.delete().queueAfter(10, TimeUnit.SECONDS));
            event.getMessage().delete().queue();
        }
        else if(!issuer.getRoles().contains(MTRole)) {
            channel.sendMessage(noPerm.build()).queue(m -> m.delete().queueAfter(10, TimeUnit.SECONDS));
            //event.getMessage().delete().queue();
        }

        String amount = String.join("", args.subList(0,1));

        if(Integer.parseInt(amount) == 1) {
            purgeMessages(channel, Integer.parseInt(amount) + 1);
        }
        else
        {
            purgeMessages(channel, Integer.parseInt(amount));
        }
    }

    public void purgeMessages(TextChannel channel, int num) {
        MessageHistory history = new MessageHistory(channel);
        List<Message> msgs;
        msgs = history.retrievePast(num).complete();
        //channel.deleteMessages(msgs).queue();
        channel.deleteMessages(msgs).queue();
    }

    @Override
    public String getHelp() {
        return "Clears messages in a channel.";
    }

    @Override
    public String getInvoke() {
        return "clear";
    }
}

This is the error I'm receiving:

net.dv8tion.jda.api.exceptions.ErrorResponseException: 10008: Unknown Message
    at net.dv8tion.jda.api.exceptions.ErrorResponseException.create(ErrorResponseException.java:157)
    at net.dv8tion.jda.api.requests.Request.onFailure(Request.java:102)
    at net.dv8tion.jda.internal.requests.RestActionImpl.handleResponse(RestActionImpl.java:239)
    at net.dv8tion.jda.api.requests.Request.handleResponse(Request.java:197)
    at net.dv8tion.jda.internal.requests.Requester.lambda$attemptRequest$1(Requester.java:191)
    at net.dv8tion.jda.internal.requests.FunctionalCallback.onResponse(FunctionalCallback.java:60)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:216)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: net.dv8tion.jda.api.exceptions.ContextException: null
    at net.dv8tion.jda.api.exceptions.ContextException.here(ContextException.java:52)
    at net.dv8tion.jda.api.requests.Request.<init>(Request.java:62)
    at net.dv8tion.jda.internal.requests.RestActionImpl.queue(RestActionImpl.java:168)
    at net.dv8tion.jda.api.requests.RestAction.lambda$queueAfter$2(RestAction.java:716)
    at net.dv8tion.jda.internal.utils.ContextRunnable.run(ContextRunnable.java:48)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:299)
    ... 3 common frames omitted
MinnDevelopment commented 4 years ago

You're sending messages that you then bulk delete and shortly after delete with queueAfter. The second delete will trigger this error because the message no longer exists. This is intended behavior. You can use the failure callback ErrorResponseException.ignore(...) to suppress specific error codes like this.

The reason this might behave differently per instance is that your code has race-conditions due to your use of queue() which is async. The message you're sending might be sent before or after the messages from the history are retrieved.

I highly recommend changing this code to not use complete() anywhere and replace deleteMessages with purgeMessages.