429 Error When Subscribing to EventSub

Hello,

Facing a strange issue. After upgrading to EventSub websockets from PubSub, some of our users reported that they cannot subscribe to any Twitch events, logs below:

[TwitchWebSocketClient] Connecting to EventSub WebSocket
[TwitchWebSocketClient] WebSocket connection established
[TwitchWebSocketClient] Received message: {"metadata":{"message_id":"c01c0a3e-93e9-4ed9-8f88-f53f0b83c6ca","message_type":"session_welcome","message_timestamp":"2025-03-28T06:58:50.22334164Z"},"payload":{"session":{"id":"AgoQ5vFpwH7QQxGDR1L5my0WmxIGY2VsbC1i","status":"connected","connected_at":"2025-03-28T06:58:50.219147346Z","keepalive_timeout_seconds":10,"reconnect_url":null,"recovery_url":null}}}
[TwitchWebSocketClient] [TwitchWebSocketClient] Session established with ID: AgoQ5vFpwH7QQxGDR1L5my0WmxIGY2VsbC1i
[TwitchWebSocketClient] Failed to subscribe to channel.channel_points_custom_reward_redemption.add: HTTP/1.1 429 Too Many Requests
{"error":"Too Many Requests","status":429,"message":"number of websocket transports limit exceeded"}

Relevant code:

public async UniTask CreateEventSubSubscription(string type, string version, Dictionary < string, string > condition, string sessionId) {
  var subscription = new {
    type,
    version,
    condition,
    transport = new {
      method = "websocket",
        session_id = sessionId
    }
  };

  string jsonPayload = JsonConvert.SerializeObject(subscription);

  using
  var uwr = new UnityWebRequest(EventSubCreateSubscriptionUrl, UnityWebRequest.kHttpVerbPOST);
  uwr.SetRequestHeader("Client-ID", ClientId);
  uwr.SetRequestHeader("Authorization", $ "Bearer {AccessToken}");
  uwr.SetRequestHeader("Content-Type", "application/json");
  uwr.downloadHandler = new DownloadHandlerBuffer();
  uwr.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(jsonPayload));

  try {
    await uwr.SendWebRequest();

    if (uwr.result == UnityWebRequest.Result.ConnectionError ||
      uwr.result == UnityWebRequest.Result.ProtocolError) {
      Debug.LogError($"[TwitchPlugin] EventSub Error: {uwr.error}, Response: {uwr.downloadHandler.text}");

      // 401 Unauthorized?
      if (uwr.responseCode == 401) {
        Debug.Log("[TwitchPlugin] OAuth token is invalid, refreshing");
        await client.RefreshToken();
        await CreateEventSubSubscription(type, version, condition, sessionId);
      }
    } else {
      Debug.Log($"[TwitchPlugin] EventSub Subscription Created: {type}");
    }
  } catch (Exception e) {
    Debug.LogError($"[TwitchPlugin] Error creating EventSub subscription: {e.Message}");
    throw;
  }
}

The strange part is, this only happens to some of our users. I can never reproduce this on my end using my account. Some more details:

  • For both working and non-working users, the AccessToken is freshly acquired.
  • For both working and non-working users, the same events are subscribed, but for the non-working users, they fail subscribing to the very first event.
  • I thought this is a “our app has too many concurrent users” issue, but I have tried subscribing to EventSub at the same time as the other user (with different Twitch accounts, of course), and I succeeded while they had a 429.

Can any Twitch engineers explain the error (number of websocket transports limit exceeded) and suggest what might lead to it? That’d be really appreciated. Thanks!

As per the documentation Handling WebSocket Events | Twitch Developers

It would seem you are trying to open a fourth websocket for a user

Edit: possible edgecases/hiccups

  • Code makes additional connections to the websocket and holds onto the old socket keeping it alive
  • Running multiple instances of the software perhaps on multiple computers

Normally I’d say “use get eventsubs” and check what subscriptions are active but you likely do not have an affected users access token handy in order to call the API can could active subscriptions. But that would just confirm that active subscriptions exist and theres 3 of a given userID/condition them

I have verified from the log that the user had only connected to the WebSocket once before triggering this error immediately. Our app runs on Steam and it’s an avatar tracking software, so it’s very unlikely the user is running it on 4+ computers simultaneously.

I will double check our code to make sure I don’t miss anything!

That could suggest that on closing the program it’s not actually closing. And thus hanging around in the background and keeping the socket alive that it’s using

So on fourth launch theres four instances running.

Since this is client/user auth I doubt they are doing anything with your clientID to cause this (since it’s implict or DCF auth (likely the latter)).

I’ve got nothing obvious beyond “there are three other websockets alive of the given clientID/user tuple holding subscriptions open”

Don’t suppose it’s something silly like instead of adding subscriptions to the existing socket a new socket is made per subscription (I don’t know how many topics/types you are connecting to)

In a test

  • made 3 seperate browser windows of my test example and authed in
  • made a foruth (after auth) the error was maximum subscriptions with type and condition exceeded
  • if I go to socket/browser 1 and delete one of the subscriptions socket 4 then gets number of websocket transports limit exceeded on the subscription that I deleted in 1.

So this could suggest you are making extra sockets (one for each type?) instead of reusing an established socket. Which might be down to a race condition in your code perhaps? (just spit balling thoughts/ideas)

So:

  • 3 sockets with the same subscription set, socket 4 gets a maximum subscriptions with type and condition exceeded
  • 3 sockets with some subs, socket 4 with a different sub to the other 3 number of websocket transports limit exceeded

Thanks for the suggestion! The user (well, actually there are two of them) tried restarting PC, re-login (i.e. redo the OAuth process), and the error was always number of websocket transports limit exceeded. My app uses the same socket to subscribe to the same set of subscriptions, but from their logs there was never a maximum subscriptions with type and condition exceeded.

The worst is the same error happens consistently with some users, and for others it works consistently. I tried reproducing this by relaunching the app a lot locally within a short period of time, but couldn’t produce the error. :smiling_face_with_tear:

Here is the full C# class: TwitchWebSocketClient.cs · GitHub

It would be prudent in that case to log the sockets and their session ID’s that the application opens/creates. I see on 161 you log the session ID’s when you get this error did the full log for that run only indicate one session ID?

Then on that error capture/log all of the subscriptions from [get eventsubs subscriptions] (Reference | Twitch Developers) (with state filter of enabled) and cross ref. So you see what the app opened/thinks it’s opened and what is currently state enabled.

Since this smells like race condition/order of operations (but would need multiple sockets to be open). epseically if the order you HTTP POST to create subscriptions is “inconsistent”

as an aside:

        private const string ChannelSubscription = "channel.subscribe";
        private const string ChannelSubscriptionVersion = "1";
        private const string ChannelSubscriptionGift = "channel.subscription.gift";
        private const string ChannelSubscriptionGiftVersion = "1";
        private const string ChannelSubscriptionMessage = "channel.subscription.message";

can probably swap those three for channel.chat.notification instead.

I’m not discussing “Twitch Sent a reconnect” since this seems to be related to launch of the app and not a twitch mandaged reconnect. (due to the user consistency)

I’d also speculate about if theres weird networking on the two users computers/ISP’s leading to schnanigans in the app and spawning extra sockets in error