Ошибка "Данный ключ отсутствует в словаре" при скачивании файла

Иногда при скачивании файла в многопотоке возникает ошибка “Данный ключ отсутствует в словаре”.
Снимок экрана 2023-11-28 152219
Полный текст ошибки:

Подробная информация об использовании оперативной 
(JIT) отладки вместо данного диалогового 
окна содержится в конце этого сообщения.

************** Текст исключения **************
System.Collections.Generic.KeyNotFoundException: Данный ключ отсутствует в словаре.
   в System.ThrowHelper.ThrowKeyNotFoundException()
   в System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   в MultiThreadedDownloaderLib.MultiThreadedDownloader.<Download>d__103.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в YouTube_downloader.FrameYouTubeVideo.<DownloadYouTubeMediaTrack>d__44.MoveNext() в H:\Projects\CSharp\YouTube downloader\YouTube downloader\FrameYouTubeVideo.cs:строка 682
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в YouTube_downloader.FrameYouTubeVideo.<DownloadTracks>d__46.MoveNext() в H:\Projects\CSharp\YouTube downloader\YouTube downloader\FrameYouTubeVideo.cs:строка 1116
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в YouTube_downloader.FrameYouTubeVideo.<MenuItemDownloadClick>d__45.MoveNext() в H:\Projects\CSharp\YouTube downloader\YouTube downloader\FrameYouTubeVideo.cs:строка 945
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()


************** Загруженные сборки **************
mscorlib
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9181.0 built by: NET481REL1LAST_C
    CodeBase: file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll
----------------------------------------
YouTubeDownloader
    Версия сборки: 1.0.0.0
    Версия Win32: 1.0.0.0
    CodeBase: file:///H:/Projects/CSharp/YouTube%20downloader/YouTube%20downloader/bin/x64/Release/YouTubeDownloader.exe
----------------------------------------
System.Windows.Forms
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9181.0 built by: NET481REL1LAST_C
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9172.0 built by: NET481REL1LAST_C
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System.Configuration
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Core
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9181.0 built by: NET481REL1LAST_C
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
----------------------------------------
System.Xml
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
ObjectListView
    Версия сборки: 2.9.1.1072
    Версия Win32: 2.9.1.0
    CodeBase: file:///H:/Projects/CSharp/YouTube%20downloader/YouTube%20downloader/bin/x64/Release/ObjectListView.DLL
----------------------------------------
System.Windows.Forms.resources
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms.resources/v4.0_4.0.0.0_ru_b77a5c561934e089/System.Windows.Forms.resources.dll
----------------------------------------
YouTubeApiLib
    Версия сборки: 0.1.4.0
    Версия Win32: 0.1.4.0
    CodeBase: file:///H:/Projects/CSharp/YouTube%20downloader/YouTube%20downloader/bin/x64/Release/YouTubeApiLib.DLL
----------------------------------------
netstandard
    Версия сборки: 2.0.0.0
    Версия Win32: 4.8.9032.0
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/netstandard/v4.0_2.0.0.0__cc7b13ffcd2ddd51/netstandard.dll
----------------------------------------
Newtonsoft.Json
    Версия сборки: 13.0.0.0
    Версия Win32: 13.0.1.25517
    CodeBase: file:///H:/Projects/CSharp/YouTube%20downloader/YouTube%20downloader/bin/x64/Release/Newtonsoft.Json.DLL
----------------------------------------
System.Numerics
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Numerics/v4.0_4.0.0.0__b77a5c561934e089/System.Numerics.dll
----------------------------------------
MultiThreadedDownloader
    Версия сборки: 1.3.0.0
    Версия Win32: 1.3.0.0
    CodeBase: file:///H:/Projects/CSharp/YouTube%20downloader/YouTube%20downloader/bin/x64/Release/MultiThreadedDownloader.DLL
----------------------------------------
System.Runtime.Serialization
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Runtime.Serialization/v4.0_4.0.0.0__b77a5c561934e089/System.Runtime.Serialization.dll
----------------------------------------
mscorlib.resources
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/mscorlib.resources/v4.0_4.0.0.0_ru_b77a5c561934e089/mscorlib.resources.dll
----------------------------------------
Microsoft.VisualBasic
    Версия сборки: 10.0.0.0
    Версия Win32: 14.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/Microsoft.VisualBasic/v4.0_10.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualBasic.dll
----------------------------------------
System.Management
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Management/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Management.dll
----------------------------------------
System.resources
    Версия сборки: 4.0.0.0
    Версия Win32: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.resources/v4.0_4.0.0.0_ru_b77a5c561934e089/System.resources.dll
----------------------------------------

************** Оперативная отладка (JIT) **************
Для подключения оперативной (JIT) отладки файл .config данного
приложения или компьютера (machine.config) должен иметь
значение jitDebugging, установленное в секции system.windows.forms.
Приложение также должно быть скомпилировано с включенной
отладкой.

Например:

<configuration>
    <system.windows.forms jitDebugging="true" />
</configuration>

При включенной отладке JIT любое необрабатываемое исключение
пересылается отладчику JIT, зарегистрированному на данном компьютере,
вместо того чтобы обрабатываться данным диалоговым окном.

Я так понимаю, это где-то тут :thinking:

            DownloadStarted?.Invoke(this, ContentLength);

            Dictionary<int, DownloadProgressItem> threadProgressDict = new Dictionary<int, DownloadProgressItem>();
            Progress<DownloadProgressItem> progress = new Progress<DownloadProgressItem>();
            progress.ProgressChanged += (s, progressItem) =>
            {
                threadProgressDict[progressItem.TaskId] = progressItem;

                DownloadedBytes = threadProgressDict.Values.Select(it => it.ProcessedBytes).Sum();

                DownloadProgress?.Invoke(this, DownloadedBytes);
            };

....

                downloader.WorkProgress += (object sender, long transfered, long contentLen) =>
                {
                    int currentTime = Environment.TickCount;
                    if (currentTime - lastTime >= UpdateIntervalMilliseconds)
                    {
                        FileChunk fileChunk = new FileChunk(chunkFileName, (streamChunk is MemoryStream) ? streamChunk : null);
                        DownloadProgressItem progressItem = new DownloadProgressItem(fileChunk, taskId, transfered, chunkLastByte);
                        reporter.Report(progressItem);

                        lastTime = currentTime;
                    }
                };

Может IProgress на что-нибудь заменить? :thinking: Не нравится он мне :man_shrugging:
Полный код:

Ошибка возникает очень редко. Началось где-то полтора года назад, когда ютуб начал блокировать сторонние скачивалки и пришлось искать обходные пути. Не знаю, может не с этим связано :man_shrugging:

Не знаю, может не с этим связано

У Вас уже была точно такая же ошибка. Связано это с тем, что Вы используете структуры данных с несинхронизированным доступом в многопоточных сценариях.

Можно на “ты” и с маленькой буквы.

Но там IProgress не было. А тут он есть. Как бы не должно быть такой ошибки :thinking: И частота выполнения обработчика тут намного выше. А ошибка возникает раз в две недели, а там почти каждый десятый раз.

магия