Fix duplicate threads causing a crash when exporting in parallel (#1486)

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot 2026-02-26 17:19:07 +02:00 committed by GitHub
parent d2c0e2169b
commit ad1170b42e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -429,6 +429,11 @@ public class DiscordClient(
.Where(c => before is null || c.MayHaveMessagesBefore(before.Value)) .Where(c => before is null || c.MayHaveMessagesBefore(before.Value))
.ToArray(); .ToArray();
// Track yielded thread IDs to avoid duplicates that can occur when a thread transitions
// from active to archived between the two separate API calls used to fetch threads.
// https://github.com/Tyrrrz/DiscordChatExporter/issues/1433
var seenThreadIds = new HashSet<Snowflake>();
// User accounts can only fetch threads using the search endpoint // User accounts can only fetch threads using the search endpoint
if (await ResolveTokenKindAsync(cancellationToken) == TokenKind.User) if (await ResolveTokenKindAsync(cancellationToken) == TokenKind.User)
{ {
@ -472,7 +477,9 @@ public class DiscordClient(
break; break;
} }
yield return thread; if (seenThreadIds.Add(thread.Id))
yield return thread;
currentOffset++; currentOffset++;
} }
@ -511,7 +518,12 @@ public class DiscordClient(
.Pipe(parentsById.GetValueOrDefault); .Pipe(parentsById.GetValueOrDefault);
if (filteredChannels.Contains(parent)) if (filteredChannels.Contains(parent))
yield return Channel.Parse(threadJson, parent); {
var thread = Channel.Parse(threadJson, parent);
if (seenThreadIds.Add(thread.Id))
yield return thread;
}
} }
} }
@ -547,12 +559,14 @@ public class DiscordClient(
) )
{ {
var thread = Channel.Parse(threadJson, channel); var thread = Channel.Parse(threadJson, channel);
yield return thread;
currentBefore = threadJson currentBefore = threadJson
.GetProperty("thread_metadata") .GetProperty("thread_metadata")
.GetProperty("archive_timestamp") .GetProperty("archive_timestamp")
.GetString(); .GetString();
if (seenThreadIds.Add(thread.Id))
yield return thread;
} }
if (!response.Value.GetProperty("has_more").GetBoolean()) if (!response.Value.GetProperty("has_more").GetBoolean())