{"action":"created","issue":{"url":"https://api.github.com/repos/discordjs/discord.js/issues/2480","repository_url":"https://api.github.com/repos/discordjs/discord.js","labels_url":"https://api.github.com/repos/discordjs/discord.js/issues/2480/labels{/name}","comments_url":"https://api.github.com/repos/discordjs/discord.js/issues/2480/comments","events_url":"https://api.github.com/repos/discordjs/discord.js/issues/2480/events","html_url":"https://github.com/discordjs/discord.js/issues/2480","id":314431036,"number":2480,"title":"Potential memory pointer/reference issues with addRole()","user":{"login":"tiritto","id":5196829,"avatar_url":"https://avatars2.githubusercontent.com/u/5196829?v=4","gravatar_id":"","url":"https://api.github.com/users/tiritto","html_url":"https://github.com/tiritto","followers_url":"https://api.github.com/users/tiritto/followers","following_url":"https://api.github.com/users/tiritto/following{/other_user}","gists_url":"https://api.github.com/users/tiritto/gists{/gist_id}","starred_url":"https://api.github.com/users/tiritto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tiritto/subscriptions","organizations_url":"https://api.github.com/users/tiritto/orgs","repos_url":"https://api.github.com/users/tiritto/repos","events_url":"https://api.github.com/users/tiritto/events{/privacy}","received_events_url":"https://api.github.com/users/tiritto/received_events","type":"User","site_admin":false},"labels":[{"id":523302849,"url":"https://api.github.com/repos/discordjs/discord.js/labels/p:%20medium","name":"p: medium","color":"ef6556","default":false},{"id":523306242,"url":"https://api.github.com/repos/discordjs/discord.js/labels/t:%20REST","name":"t: REST","color":"31e097","default":false},{"id":523304478,"url":"https://api.github.com/repos/discordjs/discord.js/labels/t:%20caching","name":"t: caching","color":"31e097","default":false},{"id":523304413,"url":"https://api.github.com/repos/discordjs/discord.js/labels/t:%20gateway","name":"t: gateway","color":"31e097","default":false},{"id":246168563,"url":"https://api.github.com/repos/discordjs/discord.js/labels/type:%20bug","name":"type: bug","color":"af310e","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2018-04-15T16:41:24Z","updated_at":"2018-05-03T16:07:38Z","closed_at":null,"author_association":"NONE","body":"**Please describe the problem you are having in as much detail as possible:**\r\nWhen I execute this code on numerous members at once (I tested it both on my 2000+ community and on another 100+ server), some weird things happen and `addRole()` returns `<GuildMember>` of WRONG member.\r\n\r\nIt seems that for some reason `addRole()` returns `<GuildMember>` that was already processed by previous function calls, regardless of `addRole()` being now called from under another member. Some person on DiscordJS discord suggested it might be an issue with memory pointers/references.\r\n\r\nIn my original (non-sample) code I was executing `addRole()` alongside with `removeRoles()`, both being called from the same `<GuildMember>` passed by main function. What is interesting, `removeRoles()` worked just perfectly every single time, which suggest that this issue is exclusive to `addRole()`.\r\n\r\n**Include a reproducible code sample here, if possible:**\r\n```js\r\nconst Discord  = require('discord.js');\r\nconst client  = new Discord.Client();\r\n\r\n// Function that causes all problems\r\nfunction assignRole(GuildMember, Role) {\r\n    if (!GuildMember.roles.has(Role.id)) {\r\n        GuildMember.addRole(Role).then((member) => {\r\n            // Print MISMATCH if returned 'member' is not the same as original 'GuildMember', and print \"SUCCESS\" otherwise. Also include details.\r\n            if (GuildMember.id !== member.id) console.log(\"MISMATCH: Expected GuildMember: [\"+ GuildMember.displayName +\"], returned GuildMember: [\"+ member.displayName +\"] \");\r\n            else console.log(\"SUCCESS:  Expected GuildMember: [\"+ GuildMember.displayName +\"], returned GuildMember: [\"+ member.displayName +\"] \");\r\n        });\r\n    }\r\n}\r\n\r\nclient.on('message', message => {\r\n    if (message.content == \"debugNow\") {\r\n        message.guild.fetchMembers().then((guild) => {\r\n\r\n            // We have 5 sample roles: A, B, C, D, E\r\n            let roleA = guild.roles.find(role => role.name === 'A');\r\n            let roleB = guild.roles.find(role => role.name === 'B');\r\n            let roleC = guild.roles.find(role => role.name === 'C');\r\n            let roleD = guild.roles.find(role => role.name === 'D');\r\n            let roleE = guild.roles.find(role => role.name === 'E');\r\n            let roleCollection = [roleA, roleB, roleC, roleD, roleE];\r\n\r\n            for (let GuildMember of guild.members.values()) {\r\n                let randomizedIndex = Math.floor(Math.random() * roleCollection.length);\r\n                assignRole(GuildMember, roleCollection[randomizedIndex]);\r\n            }\r\n        })\r\n    }\r\n});\r\n```\r\n\r\n**Further details:**\r\n\r\n- discord.js version: 11.3.0\r\n- node.js version: 9.9.0\r\n- Operating system: Debian 9 with Linux kernel 4.9.0-5-amd64\r\n- Priority this issue should have: 3.5 / 5 Priority, above Medium but below Very High\r\n"},"comment":{"url":"https://api.github.com/repos/discordjs/discord.js/issues/comments/386348654","html_url":"https://github.com/discordjs/discord.js/issues/2480#issuecomment-386348654","issue_url":"https://api.github.com/repos/discordjs/discord.js/issues/2480","id":386348654,"user":{"login":"kyranet","id":24852502,"avatar_url":"https://avatars0.githubusercontent.com/u/24852502?v=4","gravatar_id":"","url":"https://api.github.com/users/kyranet","html_url":"https://github.com/kyranet","followers_url":"https://api.github.com/users/kyranet/followers","following_url":"https://api.github.com/users/kyranet/following{/other_user}","gists_url":"https://api.github.com/users/kyranet/gists{/gist_id}","starred_url":"https://api.github.com/users/kyranet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kyranet/subscriptions","organizations_url":"https://api.github.com/users/kyranet/orgs","repos_url":"https://api.github.com/users/kyranet/repos","events_url":"https://api.github.com/users/kyranet/events{/privacy}","received_events_url":"https://api.github.com/users/kyranet/received_events","type":"User","site_admin":false},"created_at":"2018-05-03T16:07:38Z","updated_at":"2018-05-03T16:07:38Z","author_association":"CONTRIBUTOR","body":"This issue is most likely fixed:\r\n\r\nIt could happen anywhere at any moment, in 11.x, we listen to gateway events when we edit a member in order to patch it, therefore, we are creating new `guildMemberUpdate` listeners every time you add/remove a role, and same behavior is applied to many other endpoints. However, when we emit that event, it fires all listeners, included the ones we use in our `RESTManager` (where we do our \"magic\" to patch the members with those events), and as they weren't guarded by member id, any member that were to fire that event that didn't have that role but does after the patch would get returned, the affected line is here: https://github.com/discordjs/discord.js/blob/11.3.0/src/client/rest/RESTMethods.js#L532\r\n\r\nNormally, we `await` promises when we do multiple API requests, that way we add one role after another, without getting ratelimited (it's more API friendly). In your case, you weren't awaiting them, so if you were to edit two members at the same time with the same role, both `GuildMember#addRole`s would resolve with the first `GuildMember` that successfully resolves. Fortunately, this is (most likely) fixed in 11.3-dev.\r\n\r\nI have tested your code with some minor tweaks and I cannot reproduce it anymore:\r\n\r\n```javascript\r\nconst { Client } = require('discord.js');\r\nnew Client()\r\n    .on('message', async (message) => {\r\n        if (!message.content.startsWith('!test')) return;\r\n\r\n        // Get a role\r\n        const role = message.guild.roles.get('379333849076858885');\r\n\r\n        for (const member of message.guild.members.values()) {\r\n            if (member.roles.has(role.id)) {\r\n                // If the GuildMember has the role, ignore them\r\n                continue;\r\n            }\r\n\r\n            // Add the role without awaiting, to cause the racecondition\r\n            member.addRole(role).then((patched) => console.log(patched.id !== member.id\r\n                // From #2480\r\n                ? `MISMATCH: Field 'id' do not match | Expected: ${member.id}, Got ${patched.id}.`\r\n                // Else, it should be fine\r\n                : 'SUCCESS'\r\n            ));\r\n        }\r\n    })\r\n    .on('ready', () => console.log('Ready!'))\r\n    .on('error', console.error)\r\n    .on('warn', console.warn)\r\n    .login(require('./config').token);\r\n```\r\n\r\nWhich logged in for a guild with 6 members:\r\n\r\n```prolog\r\n> node .\\index.js\r\nReady!\r\nSUCCESS\r\nSUCCESS\r\nSUCCESS\r\nSUCCESS\r\nSUCCESS\r\nSUCCESS\r\n```"}}
{"actor":{"display_login":"kyranet"}}