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

Redundant Message Update Events #10153

Closed
Bloonatics opened this issue Feb 26, 2024 · 2 comments
Closed

Redundant Message Update Events #10153

Bloonatics opened this issue Feb 26, 2024 · 2 comments
Labels

Comments

@Bloonatics
Copy link

Which package is this bug report for?

discord.js

Issue description

Setup

const { Client, GatewayIntentBits } = require('discord.js');
const { writeFileSync } = require('fs');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent
  ]
});

client.debug = [];

setInterval(() => writeFileSync('./debug.json', JSON.stringify(client.debug, null, '\t')), 1e4);

client.login('token');

this._ws.on(WSWebSocketShardEvents.Dispatch, ({ data, shardId }) => {
this.client.emit(Events.Raw, data, shardId);
this.emit(data.t, data.d, shardId);
const shard = this.shards.get(shardId);
this.handlePacket(data, shard);
if (shard.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(data.t)) {
shard.gotGuild(data.d.id);
}
});

    this._ws.on(WSWebSocketShardEvents.Dispatch, ({ data, shardId }) => {
+     if (data.t === 'MESSAGE_UPDATE') {
+       this.client.debug.push(data);
+       console.log(data);
+     }
+
      this.client.emit(Events.Raw, data, shardId);
      this.emit(data.t, data.d, shardId);
      const shard = this.shards.get(shardId);
      this.handlePacket(data, shard);
      if (shard.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(data.t)) {
        shard.gotGuild(data.d.id);
      }
    });

Specification

Guilds

  • 740192346024443964 - 16 members (903556716547960862 is a text channel there)
  • 678164358378946580 - about 22k members (748114061966835772 is a text channel there)

Users

  • 676103178323886085 - my account (non bot)
  • 866765758566236200 - the client to run this experiment (bot)
  • 826343609824575504 - another bot

Experiment

1. user 676103178323886085 channel 903556716547960862 (non bot in smaller guild)

Send a message with content . and edit it to ..

./debug.json

[
	{
		"t": "MESSAGE_UPDATE",
		"s": 10,
		"op": 0,
		"d": {
			"type": 0,
			"tts": false,
			"timestamp": "2024-02-26T11:42:24.611000+00:00",
			"pinned": false,
			"mentions": [],
			"mention_roles": [],
			"mention_everyone": false,
			"member": {
				"roles": [
					"827910959871164486"
				],
				"premium_since": null,
				"pending": false,
				"nick": "Bloonatics",
				"mute": false,
				"joined_at": "2020-08-04T13:00:07.411000+00:00",
				"flags": 0,
				"deaf": false,
				"communication_disabled_until": null,
				"avatar": null
			},
			"id": "1211639402011299850",
			"flags": 0,
			"embeds": [],
			"edited_timestamp": "2024-02-26T11:42:27.317791+00:00",
			"content": "..",
			"components": [],
			"channel_id": "903556716547960862",
			"author": {
				"username": "bloonatics",
				"public_flags": 4194432,
				"premium_type": 0,
				"id": "676103178323886085",
				"global_name": "Bloonatics",
				"discriminator": "0",
				"avatar_decoration_data": null,
				"avatar": "a236da7641db588ca84c75541a8c8759"
			},
			"attachments": [],
			"guild_id": "740192346024443964"
		}
	}
]

There's no problem, it fires a single MESSAGE_UPDATE event.

2. user 676103178323886085 channel 748114061966835772 (non bot in larger guild)

Send a message with content . and edit it to ..

./debug.json

[
	{
		"t": "MESSAGE_UPDATE",
		"s": 12,
		"op": 0,
		"d": {
			"type": 0,
			"tts": false,
			"timestamp": "2024-02-26T11:43:17.783000+00:00",
			"pinned": false,
			"mentions": [],
			"mention_roles": [],
			"mention_everyone": false,
			"member": {
				"roles": [
					"756248495110881360",
					"995756877075988570",
					"986909666820898867"
				],
				"premium_since": null,
				"pending": false,
				"nick": "Bloonatics 🌸",
				"mute": false,
				"joined_at": "2020-04-24T06:59:30.136000+00:00",
				"flags": 2,
				"deaf": false,
				"communication_disabled_until": null,
				"avatar": null
			},
			"id": "1211639625031094293",
			"flags": 0,
			"embeds": [],
			"edited_timestamp": "2024-02-26T11:43:20.363021+00:00",
			"content": "..",
			"components": [],
			"channel_id": "748114061966835772",
			"author": {
				"username": "bloonatics",
				"public_flags": 4194432,
				"premium_type": 0,
				"id": "676103178323886085",
				"global_name": "Bloonatics",
				"discriminator": "0",
				"avatar_decoration_data": null,
				"avatar": "a236da7641db588ca84c75541a8c8759"
			},
			"attachments": [],
			"guild_id": "678164358378946580"
		}
	}
]

There's no problem, it fires a single MESSAGE_UPDATE event.

3. user 826343609824575504 channel 903556716547960862 (bot in smaller guild)

Run /ping, what the bot does are

  1. ChatInputCommandInteraction#reply
  2. ChatInputCommandInteraction#editReply

./debug.json

[
	{
		"t": "MESSAGE_UPDATE",
		"s": 84,
		"op": 0,
		"d": {
			"webhook_id": "826343609824575504",
			"type": 20,
			"tts": false,
			"timestamp": "2024-02-26T12:06:35.005000+00:00",
			"position": 0,
			"pinned": false,
			"mentions": [],
			"mention_roles": [],
			"mention_everyone": false,
			"member": {
				"roles": [
					"740204079099412520",
					"826345824548159498",
					"846064947838189588"
				],
				"premium_since": null,
				"pending": false,
				"nick": null,
				"mute": false,
				"joined_at": "2021-03-30T06:43:17.346000+00:00",
				"flags": 0,
				"deaf": false,
				"communication_disabled_until": null,
				"avatar": null
			},
			"interaction_metadata": {
				"user_id": "676103178323886085",
				"type": 2,
				"name": "ping",
				"id": "1211645484456738897",
				"authorizing_integration_owners": {
					"0": "740192346024443964"
				}
			},
			"interaction": {
				"user": {
					"username": "bloonatics",
					"public_flags": 4194432,
					"id": "676103178323886085",
					"global_name": "Bloonatics",
					"discriminator": "0",
					"avatar_decoration_data": null,
					"avatar": "a236da7641db588ca84c75541a8c8759"
				},
				"type": 2,
				"name": "ping",
				"member": {
					"roles": [
						"827910959871164486"
					],
					"premium_since": null,
					"pending": false,
					"nick": "Bloonatics",
					"mute": false,
					"joined_at": "2020-08-04T13:00:07.411000+00:00",
					"flags": 0,
					"deaf": false,
					"communication_disabled_until": null,
					"avatar": null
				},
				"id": "1211645484456738897"
			},
			"id": "1211645485404782612",
			"flags": 0,
			"embeds": [
				{
					"type": "rich",
					"title": "Pong!",
					"footer": {
						"text": "bloonatics",
						"proxy_icon_url": "https://images-ext-2.discordapp.net/external/xRotzEa3IhzPRr5ah464AOJarA5gfjVMDeDuFVvr4ng/https/cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp",
						"icon_url": "https://cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp"
					},
					"description": "Roundtrip latency: `293ms`\nWebsocket heartbeat: `44ms`",
					"color": 12845022
				}
			],
			"edited_timestamp": "2024-02-26T12:06:35.356287+00:00",
			"content": "",
			"components": [],
			"channel_id": "903556716547960862",
			"author": {
				"username": "Bloony",
				"public_flags": 65536,
				"premium_type": 0,
				"id": "826343609824575504",
				"global_name": null,
				"discriminator": "0615",
				"bot": true,
				"avatar_decoration_data": null,
				"avatar": "a_c7b487a96f23f21aac1a54125d821714"
			},
			"attachments": [],
			"application_id": "826343609824575504",
			"guild_id": "740192346024443964"
		}
	}
]

There's no problem, it fires a single MESSAGE_UPDATE event.

4. user 826343609824575504 channel 748114061966835772 (bot in larger guild)

Run /ping, what the bot does are

  1. ChatInputCommandInteraction#reply
  2. ChatInputCommandInteraction#editReply

./debug.json

[
	{
		"t": "MESSAGE_UPDATE",
		"s": 86,
		"op": 0,
		"d": {
			"id": "1211645783686782996",
			"channel_id": "748114061966835772",
			"attachments": [],
			"guild_id": "678164358378946580"
		}
	},
	{
		"t": "MESSAGE_UPDATE",
		"s": 87,
		"op": 0,
		"d": {
			"webhook_id": "826343609824575504",
			"type": 20,
			"tts": false,
			"timestamp": "2024-02-26T12:07:46.121000+00:00",
			"position": 0,
			"pinned": false,
			"mentions": [],
			"mention_roles": [],
			"mention_everyone": false,
			"member": {
				"roles": [
					"710374276049534977",
					"986909666820898867",
					"678176821321138189",
					"742414428208758815"
				],
				"premium_since": null,
				"pending": false,
				"nick": "( b. ) Bloony 🌸",
				"mute": false,
				"joined_at": "2022-09-16T20:35:00.838000+00:00",
				"flags": 0,
				"deaf": false,
				"communication_disabled_until": null,
				"avatar": null
			},
			"interaction_metadata": {
				"user_id": "676103178323886085",
				"type": 2,
				"name": "ping",
				"id": "1211645782789201970",
				"authorizing_integration_owners": {
					"0": "678164358378946580"
				}
			},
			"interaction": {
				"user": {
					"username": "bloonatics",
					"public_flags": 4194432,
					"id": "676103178323886085",
					"global_name": "Bloonatics",
					"discriminator": "0",
					"avatar_decoration_data": null,
					"avatar": "a236da7641db588ca84c75541a8c8759"
				},
				"type": 2,
				"name": "ping",
				"member": {
					"roles": [
						"756248495110881360",
						"995756877075988570",
						"986909666820898867"
					],
					"premium_since": null,
					"pending": false,
					"nick": "Bloonatics 🌸",
					"mute": false,
					"joined_at": "2020-04-24T06:59:30.136000+00:00",
					"flags": 2,
					"deaf": false,
					"communication_disabled_until": null,
					"avatar": null
				},
				"id": "1211645782789201970"
			},
			"id": "1211645783686782996",
			"flags": 0,
			"embeds": [
				{
					"type": "rich",
					"title": "Pong!",
					"footer": {
						"text": "bloonatics",
						"proxy_icon_url": "https://images-ext-2.discordapp.net/external/xRotzEa3IhzPRr5ah464AOJarA5gfjVMDeDuFVvr4ng/https/cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp",
						"icon_url": "https://cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp"
					},
					"description": "Roundtrip latency: `241ms`\nWebsocket heartbeat: `74ms`",
					"color": 12845022
				}
			],
			"edited_timestamp": "2024-02-26T12:07:46.412817+00:00",
			"content": "",
			"components": [],
			"channel_id": "748114061966835772",
			"author": {
				"username": "Bloony",
				"public_flags": 65536,
				"premium_type": 0,
				"id": "826343609824575504",
				"global_name": null,
				"discriminator": "0615",
				"bot": true,
				"avatar_decoration_data": null,
				"avatar": "a_c7b487a96f23f21aac1a54125d821714"
			},
			"attachments": [],
			"application_id": "826343609824575504",
			"guild_id": "678164358378946580"
		}
	},
	{
		"t": "MESSAGE_UPDATE",
		"s": 88,
		"op": 0,
		"d": {
			"id": "1211645783686782996",
			"channel_id": "748114061966835772",
			"attachments": [],
			"guild_id": "678164358378946580"
		}
	}
]

We can see that there are three MESSAGE_UPDATE events with the same message id 1211645783686782996 and an ascending sequence number of event. This experiment is done with the same conditions as the 3rd experiment but in a larger guild.

Summary

After additional testing, I have found that this bug:

  • Only affects large guilds and bot users.
  • Cannot be reproduced for some bots (e.g. I can reproduce it by using 270904126974590976 but not 235148962103951360).

Code sample

No response

Versions

  • discord.js@14.14.1
  • node@21.1.0

Issue priority

Medium (should be fixed soon)

Which partials do you have configured?

No Partials

Which gateway intents are you subscribing to?

Guilds, GuildMessages, MessageContent

I have tested this issue on a development release

No response

@Jiralite
Copy link
Member

Jiralite commented Feb 26, 2024

These logs are coming from Discord, so it's not a discord.js issue. You should open an issue over at https://github.com/discord/discord-api-docs and report your findings.

@Bloonatics
Copy link
Author

Simple temporary solution for users

Warning: This assumes you only want to handle MESSAGE_UPDATE event when the author edits their messages (you can actually see the edited label in their messages from Discord's UI). If you want to handle more complex MESSAGE_UPDATE cases like component only update, embed suppression etc., please edit the if statement.

client.on(Events.MessageUpdate, (oldMsg, newMsg) => {
  if (oldMsg.editedTimestamp === newMsg.editedTimestamp) return;

  // ...
});

Reason for this to work

Take a look at the previous redundant MESSAGE_UPDATE packets:

./debug.json

[
	{
		"t": "MESSAGE_UPDATE",
		"s": 86,
		"op": 0,
		"d": {
			"id": "1211645783686782996",
			"channel_id": "748114061966835772",
			"attachments": [],
			"guild_id": "678164358378946580"
		}
	},
	{
		"t": "MESSAGE_UPDATE",
		"s": 87,
		"op": 0,
		"d": {
			"webhook_id": "826343609824575504",
			"type": 20,
			"tts": false,
			"timestamp": "2024-02-26T12:07:46.121000+00:00",
			"position": 0,
			"pinned": false,
			"mentions": [],
			"mention_roles": [],
			"mention_everyone": false,
			"member": {
				"roles": [
					"710374276049534977",
					"986909666820898867",
					"678176821321138189",
					"742414428208758815"
				],
				"premium_since": null,
				"pending": false,
				"nick": "( b. ) Bloony 🌸",
				"mute": false,
				"joined_at": "2022-09-16T20:35:00.838000+00:00",
				"flags": 0,
				"deaf": false,
				"communication_disabled_until": null,
				"avatar": null
			},
			"interaction_metadata": {
				"user_id": "676103178323886085",
				"type": 2,
				"name": "ping",
				"id": "1211645782789201970",
				"authorizing_integration_owners": {
					"0": "678164358378946580"
				}
			},
			"interaction": {
				"user": {
					"username": "bloonatics",
					"public_flags": 4194432,
					"id": "676103178323886085",
					"global_name": "Bloonatics",
					"discriminator": "0",
					"avatar_decoration_data": null,
					"avatar": "a236da7641db588ca84c75541a8c8759"
				},
				"type": 2,
				"name": "ping",
				"member": {
					"roles": [
						"756248495110881360",
						"995756877075988570",
						"986909666820898867"
					],
					"premium_since": null,
					"pending": false,
					"nick": "Bloonatics 🌸",
					"mute": false,
					"joined_at": "2020-04-24T06:59:30.136000+00:00",
					"flags": 2,
					"deaf": false,
					"communication_disabled_until": null,
					"avatar": null
				},
				"id": "1211645782789201970"
			},
			"id": "1211645783686782996",
			"flags": 0,
			"embeds": [
				{
					"type": "rich",
					"title": "Pong!",
					"footer": {
						"text": "bloonatics",
						"proxy_icon_url": "https://images-ext-2.discordapp.net/external/xRotzEa3IhzPRr5ah464AOJarA5gfjVMDeDuFVvr4ng/https/cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp",
						"icon_url": "https://cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp"
					},
					"description": "Roundtrip latency: `241ms`\nWebsocket heartbeat: `74ms`",
					"color": 12845022
				}
			],
			"edited_timestamp": "2024-02-26T12:07:46.412817+00:00",
			"content": "",
			"components": [],
			"channel_id": "748114061966835772",
			"author": {
				"username": "Bloony",
				"public_flags": 65536,
				"premium_type": 0,
				"id": "826343609824575504",
				"global_name": null,
				"discriminator": "0615",
				"bot": true,
				"avatar_decoration_data": null,
				"avatar": "a_c7b487a96f23f21aac1a54125d821714"
			},
			"attachments": [],
			"application_id": "826343609824575504",
			"guild_id": "678164358378946580"
		}
	},
	{
		"t": "MESSAGE_UPDATE",
		"s": 88,
		"op": 0,
		"d": {
			"id": "1211645783686782996",
			"channel_id": "748114061966835772",
			"attachments": [],
			"guild_id": "678164358378946580"
		}
	}
]

Focus on the first packet:

{
	"t": "MESSAGE_UPDATE",
	"s": 86,
	"op": 0,
	"d": {
		"id": "1211645783686782996",
		"channel_id": "748114061966835772",
		"attachments": [],
		"guild_id": "678164358378946580"
	}
}

Please note that this data does not have edited_timestamp and the complete structure of this message is cached because of the MESSAGE_CREATE event just before it. In this case, the Message structure of both oldMsg and newMsg are exactly the same (I know that attachments would be updated, but both are empty array in this case) plus the Message#editedTimestamp of them are both null, i.e. this data is unnecessary. We can ignore it by checking their Message#editedTimestamp.

Focus on the second packet:

{
	"t": "MESSAGE_UPDATE",
	"s": 87,
	"op": 0,
	"d": {
		"webhook_id": "826343609824575504",
		"type": 20,
		"tts": false,
		"timestamp": "2024-02-26T12:07:46.121000+00:00",
		"position": 0,
		"pinned": false,
		"mentions": [],
		"mention_roles": [],
		"mention_everyone": false,
		"member": {
			"roles": [
				"710374276049534977",
				"986909666820898867",
				"678176821321138189",
				"742414428208758815"
			],
			"premium_since": null,
			"pending": false,
			"nick": "( b. ) Bloony 🌸",
			"mute": false,
			"joined_at": "2022-09-16T20:35:00.838000+00:00",
			"flags": 0,
			"deaf": false,
			"communication_disabled_until": null,
			"avatar": null
		},
		"interaction_metadata": {
			"user_id": "676103178323886085",
			"type": 2,
			"name": "ping",
			"id": "1211645782789201970",
			"authorizing_integration_owners": {
				"0": "678164358378946580"
			}
		},
		"interaction": {
			"user": {
				"username": "bloonatics",
				"public_flags": 4194432,
				"id": "676103178323886085",
				"global_name": "Bloonatics",
				"discriminator": "0",
				"avatar_decoration_data": null,
				"avatar": "a236da7641db588ca84c75541a8c8759"
			},
			"type": 2,
			"name": "ping",
			"member": {
				"roles": [
					"756248495110881360",
					"995756877075988570",
					"986909666820898867"
				],
				"premium_since": null,
				"pending": false,
				"nick": "Bloonatics 🌸",
				"mute": false,
				"joined_at": "2020-04-24T06:59:30.136000+00:00",
				"flags": 2,
				"deaf": false,
				"communication_disabled_until": null,
				"avatar": null
			},
			"id": "1211645782789201970"
		},
		"id": "1211645783686782996",
		"flags": 0,
		"embeds": [
			{
				"type": "rich",
				"title": "Pong!",
				"footer": {
					"text": "bloonatics",
					"proxy_icon_url": "https://images-ext-2.discordapp.net/external/xRotzEa3IhzPRr5ah464AOJarA5gfjVMDeDuFVvr4ng/https/cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp",
					"icon_url": "https://cdn.discordapp.com/avatars/676103178323886085/a236da7641db588ca84c75541a8c8759.webp"
				},
				"description": "Roundtrip latency: `241ms`\nWebsocket heartbeat: `74ms`",
				"color": 12845022
			}
		],
		"edited_timestamp": "2024-02-26T12:07:46.412817+00:00",
		"content": "",
		"components": [],
		"channel_id": "748114061966835772",
		"author": {
			"username": "Bloony",
			"public_flags": 65536,
			"premium_type": 0,
			"id": "826343609824575504",
			"global_name": null,
			"discriminator": "0615",
			"bot": true,
			"avatar_decoration_data": null,
			"avatar": "a_c7b487a96f23f21aac1a54125d821714"
		},
		"attachments": [],
		"application_id": "826343609824575504",
		"guild_id": "678164358378946580"
	}
}

As we all know, this data is necessary and we want to handle it because its oldMsg and newMsg have a completely different Message structure and Message#editedTimestamp.

Focus on the third packet:

{
	"t": "MESSAGE_UPDATE",
	"s": 88,
	"op": 0,
	"d": {
		"id": "1211645783686782996",
		"channel_id": "748114061966835772",
		"attachments": [],
		"guild_id": "678164358378946580"
	}
}

You probably know what I want to say already. Since the values of the previous packet are cached, we will receive oldMsg and newMsg with exactly the same Message structure (I know that attachments would be updated, but both are empty array in this case) and Message#editedTimestamp (1708949266412 in this case). Therefore, we can ignore it with the same method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants