Exception thrown rarely when sending a message while a channel is being created
Created by: uwx
Summary
An exception with the message Collection was modified; enumeration operation may not execute.
is thrown when sending a message while a channel is being created, particularly when sending DMs to many users in a short timespan (lots of private channels getting created)
Details
The exception looks something like this:
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)
at DSharpPlus.DiscordClient.InternalGetCachedChannel(UInt64 channelId)
at DSharpPlus.Net.DiscordApiClient.PrepareMessage(JToken msg_raw)
at DSharpPlus.Net.DiscordApiClient.CreateMessageAsync(UInt64 channel_id, String content, Nullable`1 tts, DiscordEmbed embed)
at DSharpPlus.Entities.DiscordMember.SendMessageAsync(String content, Boolean is_tts, DiscordEmbed embed)
at TFNGateKeeper.Program.Ask(String question, UInt64 userid) in /home/lucas/Gatekeeper/Program.cs:line 870
at TFNGateKeeper.Program.NewUser(UInt64 userid, Boolean force) in /home/lucas/Gatekeeper/Program.cs:line 417
It is caused by an iteration through DiscordClient._privateChannels while it is being modified, but it can also happen to other properties, such as DiscordClient.Guilds or DiscordGuild.Channels.
Steps to reproduce
The code to reproduce the issue looks something like this
var obj = new object();
RayLog.Red("STARTE");
const int imbored = 100;
for (var i = 0; i < imbored * 10; i++)
{
RayLog.Red("STARTE " + i);
new Thread(() =>
{
while (true)
{
var c = new DiscordDmChannel();
lock (obj)
{
ctx.Client._privateChannels.Add(c);
}
Thread.Sleep(imbored);
lock (obj)
{
ctx.Client._privateChannels.Remove(c);
}
}
}).Start();
}
for (var i = 0; i < imbored; i++)
{
RayLog.Red("2STARTE " + i);
new Thread(() =>
{
_ = ctx.Author.SendMessageAsync("Iteration " + i);
}).Start();
}
Obviously this relies on manually adding private channels, since DMing loads of people in a short time frame would be considered API abuse. Note that even with this code it's a rare occurrence, compiling in Debug and attaching a debugger usually slows the program down enough that it can happen.
Notes
Related: #219 (closed)
This issue was reported by Lucas7yoshi on Discord.
I am fixing this issue as we speak.