Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First command after a period of inactivity fails to run (subsequent commands work fine) #616

Closed
xenanthropy opened this issue Jul 20, 2024 · 8 comments · Fixed by #617
Closed

Comments

@xenanthropy
Copy link

xenanthropy commented Jul 20, 2024

Description

I'm encountering an issue with Nostrum where the first command after a period of inactivity fails. However, if I re-run the command, it will work just fine.

Steps to Reproduce

  1. Start the bot.
  2. Let the bot sit idle for a day or so (time varies, sometimes it happens after just a few hours)
  3. Run a command after the period of inactivity.

Expected Behavior

The command should execute without errors.

Actual Behavior

The first command after a period of inactivity fails with the following error message: (I changed some of the IDs in case it's sensitive information) (( Note that both before and after the error message, i'm still getting "HEARTBEAT_ACK" messages))

Error Message

[error] ** State machine 'Elixir.Nostrum.Api.Ratelimiter' terminating
** Last event = {info,{gun_error,<0.1453.0>,
                                 #Ref<0.781311242.2420637704.134357>,closed}}
** When server state  = {connected,#{conn => <0.1453.0>,inflight => #{},
                                     outstanding =>
                                         #{<<"/interactions/_id/aW50ZXJhY3Rpb246MTI2NDMwOTg5ERW2Mzg5Njk3NTpwd3FlVndBd085aTlQR0RCZmVhb21GMTFKTXVUbUVlTWhBOEZrT
llHMjhqaGxMenl2ZE83RFFUajdiMFhuQnFBQXBralVxeGJubHNjT2RlZkdrSWp6bUttZmtnY1A4Z2VLMjlXeUNJenZrTnhKSEpTeENzYVpzSzA1NE80V1cyZA/callback">> =>
                                               {initial,{[],[]}}},
                                     remaining_in_window => 48,
                                     running =>
                                         #{#Ref<0.781311242.2420637704.134357> =>
                                               {<<"/interactions/_id/aW50ZXJhY3Rpb246MTI2NDMwOTg5ERW2Mzg5Njk3NTpwd3FlVndBd085aTlQR0RCZmVhb21GMTFKTXVUbUVlTWhB
OEZrTllHMjhqaGxMenl2ZE83RFFUajdiMFhuQnFBQXBralVxeGJubHNjT2RlZkdrSWp6bUttZmtnY1A4Z2VLMjlXeUNJenZrTnhKSEpTeENzYVpzSzA1NE80V1cyZA/callback">>,
                                                #{body => #{type => 5},
                                                  headers =>
                                                      [{<<"content-type">>,
                                                        <<"application/json">>}],
                                                  method => post,params => [],
                                                  route =>
                                                      <<"/interactions/1264309899563896975/aW50ZXJhY3Rpb246MTI2NDMwOTg5ERW2Mzg5Njk3NTpwd3FlVndBd085aTlQR0RCZm
Vhb21GMTFKTXVUbUVlTWhBOEZrTllHMjhqaGxMenl2ZE83RFFUajdiMFhuQnFBQXBralVxeGJubHNjT2RlZkdrSWp6bUttZmtnY1A4Z2VLMjlXeUNJenZrTnhKSEpTeENzYVpzSzA1NE80V1cyZA/callback
">>},
                                                {<0.1552.0>,
                                                 #Ref<0.781311242.2420637704.134356>}}},
                                     wrapped_token =>
                                         #Fun<Elixir.Nostrum.Api.Ratelimiter.4.17972570>}}
** Reason for termination = error:#{'__exception__' => true,
                                    '__struct__' =>
                                        'Elixir.Protocol.UndefinedError',
                                    description => <<>>,
                                    protocol => 'Elixir.String.Chars',
                                    value =>
                                        {<0.1552.0>,
                                         #Ref<0.781311242.2420637704.134356>}}
** Callback modules = ['Elixir.Nostrum.Api.Ratelimiter']
** Callback mode = state_functions
** Stacktrace =
**  [{'Elixir.String.Chars','impl_for!',1,
         [{file,"lib/string/chars.ex"},{line,3}]},
     {'Elixir.String.Chars',to_string,1,
         [{file,"lib/string/chars.ex"},{line,22}]},
     {'Elixir.Nostrum.Api.Ratelimiter',connected,3,
         [{file,"lib/nostrum/api/ratelimiter.ex"},{line,862}]},
     {gen_statem,loop_state_callback,11,[{file,"gen_statem.erl"},{line,1426}]},
     {proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,240}]}]
** Time-outs: {1,[{{timeout,reset_bot_calls_window},expired}]}

[error] Task #PID<0.1552.0> started from #PID<0.1472.0> terminating
** (stop) exited in: :gen_statem.call(Nostrum.Api.Ratelimiter, {:queue, %{body: %{type: 5}, headers: [{"content-type", "application/json"}], method: :post, p
arams: [], route: "/interactions/1264309893693896975/aW50ZXJhY3Rpb246MTI2NDMwOTg5ERW2Mzg5Njk3NTpwd3FlVndBd085aTlQR0RCZmVhb21GMTFKTXVUbUVlTWhBOEZrTllHMjhqaGxM
enl2ZE83RFFUajdiMFhuQnFBQXBralVxeGJubHNjT2RlZkdrSWp6bUttZmtnY1A4Z2VLMjlXeUNJenZrTnhKSEpTeENzYVpzSzA1NE80V1cyZA/callback"}}, :infinity)
    ** (EXIT) an exception was raised:
        ** (Protocol.UndefinedError) protocol String.Chars not implemented for {#PID<0.1552.0>, #Reference<0.781311242.2420637704.134356>} of type Tuple. Thi
s protocol is implemented for the following type(s): Atom, BitString, Date, DateTime, Float, Integer, List, NaiveDateTime, Nostrum.Struct.Channel, Nostrum.St
ruct.Emoji, Nostrum.Struct.Guild.Member, Nostrum.Struct.Guild.Role, Nostrum.Struct.User, Time, URI, Version, Version.Requirement
            (elixir 1.16.2) lib/string/chars.ex:3: String.Chars.impl_for!/1
            (elixir 1.16.2) lib/string/chars.ex:22: String.Chars.to_string/1
            (nostrum 0.10.0) lib/nostrum/api/ratelimiter.ex:862: Nostrum.Api.Ratelimiter.connected/3
            (stdlib 4.3) gen_statem.erl:1426: :gen_statem.loop_state_callback/11
            (stdlib 4.3) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
    (stdlib 4.3) gen.erl:243: :gen.do_call/4
    (stdlib 4.3) gen_statem.erl:900: :gen_statem.call_dirty/4
    (kyoko 0.1.0) lib/kyoko/kyoko.ex:85: Kyoko.handle_event/1
    (elixir 1.16.2) lib/task/supervised.ex:101: Task.Supervised.invoke_mfa/2
Function: #Function<3.34583683/0 in Kyoko.handle_info/2>
    Args: []

I'll include my handle_event function in case it's relevant:

  def handle_event({:INTERACTION_CREATE, interaction, _ws_state}) do
    user_tags =
      if interaction.data.options do
        interaction.data.options
        |> Enum.find(fn option -> option.name == "tags" end)
        |> then(fn option -> option.value || "" end) || ""
      else
        # Default value for no tags option
        # Defaulting to 1girl because no tags takes too long for the API and fails often..
        "1girl"
      end

    case check_tags(user_tags) do
      {:restricted, restricted} ->
        Api.create_interaction_response(interaction, %{
          type: 4,
          data: %{content: restricted, flags: 64}
        })

      {:invalid, invalid} ->
        Api.create_interaction_response(interaction, %{
          type: 4,
          data: %{content: invalid, flags: 64}
        })

      {:valid, restricted_tags, bypass} ->
        case bypass do
          # making the bypass ephemeral in case a user generates something... questionable
          true -> Api.create_interaction_response(interaction, %{type: 5, data: %{flags: 64}})
          false -> Api.create_interaction_response(interaction, %{type: 5})
        end

        case generate_image(user_tags, restricted_tags, bypass) do
          {:msg, url, image_id} ->
            Api.edit_interaction_response(
              interaction.token,
              build_embed_response(url, image_id)
            )

          {:no_posts, error_message} ->
            # have to delete original interaction since we can't change a non-ephemeral interaction response to ephemeral
            # also have to edit interaction response first, otherwise `delete` will delete the followup message too...
            if bypass do
              Api.edit_interaction_response(interaction.token, %{content: error_message})
            else
              Api.edit_interaction_response(interaction.token, %{content: "error"})
              Api.create_followup_message(interaction.token, %{content: error_message, flags: 64})
              Api.delete_interaction_response(interaction)
            end


          _ ->
            # Handle unexpected return values from generate_image()
            IO.warn("Unexpected response from generate_image: #{inspect(interaction)}")

            Api.edit_interaction_response(interaction.token, %{
              content: "Unexpected error, sorry! :("
            })
        end
    end
  end
@xenanthropy
Copy link
Author

Oops i'm a dummy, didn't even notice a new release! I see the Key error in the ratelimiter has been fixed, silly me :) Guess i'll update, heh

@xenanthropy
Copy link
Author

xenanthropy commented Jul 20, 2024

Ah, nevermind! I'm no longer getting the Key error, it's a different error now, lovely :) I've updated the original post to match the new error, it's the same structure as the Key error though

@xenanthropy xenanthropy reopened this Jul 20, 2024
@Th3-M4jor
Copy link
Contributor

The {gun_error,<0.1453.0>,#Ref<0.781311242.2420637704.134357>,closed} would suggest this is an issue with your network stack somewhere along the line. As this would suggest the http connection is being closed by Cloudflare or Discord.

@xenanthropy
Copy link
Author

The {gun_error,<0.1453.0>,#Ref<0.781311242.2420637704.134357>,closed} would suggest this is an issue with your network stack somewhere along the line. As this would suggest the http connection is being closed by Cloudflare or Discord.

Hmm, odd... For now i've just been running the bot on my home network - I plan on putting it on my VPS soon but I didn't see the point in doing that until it was mostly complete. I guess i'll see if I still have the issue once i'm running it on that

jchristgit added a commit that referenced this issue Jul 22, 2024
@jchristgit
Copy link
Collaborator

The clue here is this:

** Reason for termination = error:#{'__exception__' => true,
                                    '__struct__' =>
                                        'Elixir.Protocol.UndefinedError',
                                    description => <<>>,
                                    protocol => 'Elixir.String.Chars',
                                    value =>
                                        {<0.1552.0>,
                                         #Ref<0.781311242.2420637704.134356>}}
** Callback modules = ['Elixir.Nostrum.Api.Ratelimiter']
** Callback mode = state_functions
** Stacktrace =
**  [{'Elixir.String.Chars','impl_for!',1,
         [{file,"lib/string/chars.ex"},{line,3}]},
     {'Elixir.String.Chars',to_string,1,
         [{file,"lib/string/chars.ex"},{line,22}]},
     {'Elixir.Nostrum.Api.Ratelimiter',connected,3,
         [{file,"lib/nostrum/api/ratelimiter.ex"},{line,862}]},
     {gen_statem,loop_state_callback,11,[{file,"gen_statem.erl"},{line,1426}]},
     {proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,240}]}]

nostrum correctly heads into its requeue routine, but then crashes because of broken string formatting.

I pushed a fix for this.

Btw, another question. Your original issue (pre-edit) had a different traceback, was that another bug?

@xenanthropy
Copy link
Author

xenanthropy commented Jul 22, 2024

Ah thanks for the fix!

And yeah my previous stacktrace had to do with the Key error that was patched in the most recent release, I believe (#606 was the commit). At least - I didn't have that specific error anymore once i'd updated! I hadn't noticed there was a new release when i'd originally posted my issue :) If I do run into that issue again though i'll make another issue. Assuming I don't run into any other problems, are we able to mark this as solved?

@jchristgit
Copy link
Collaborator

jchristgit commented Jul 22, 2024 via email

@xenanthropy
Copy link
Author

Ok, sounds good - thanks for the fix!

Kraigie pushed a commit that referenced this issue Jul 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants