bugsnag-unity icon indicating copy to clipboard operation
bugsnag-unity copied to clipboard

InvalidOperationException Collection was modified; enumeration operation may not execute

Open gagbaghdas opened this issue 10 months ago • 4 comments

Describe the bug

I'm seeing exceptions coming from BugsnagUnity.Client.

Steps to reproduce

I couldn't reproduce when the exception is being thrown, so can't give exact stepts.

Environment

  • Bugsnag version: 7.7.1 bugsnag-unity-upm-edm4u version.
  • Unity version: 2021.3.28f1
  • iOS/Android/macOS/Windows/browser version:
  • simulator/emulator or physical device: physical device - Android. Not sure about iOS.
  • Initializing bugsnag via a Unity GameObject or in code?: via GameObject
  • Player Settings:
    • Scripting backend (Mono or IL2CPP): IL2CPP
    • API compatibility level for .NET:
    • Stack Trace level for all error types (None/ScriptOnly/Full): Provided

Example Repo

  • [ ] Create a minimal repository that can reproduce the issue
  • [ ] Link to it here:

Example code snippet

# (Insert code sample to reproduce the problem)
Error messages:
InvalidOperationException Collection was modified; enumeration operation may not execute. 
    <00000000000000000000000000000000> System.Collections.Generic.List`1+Enumerator[T].MoveNext()
    <00000000000000000000000000000000> BugsnagUnity.Client.NotifyOnMainThread(BugsnagUnity.Payload.Error[] exceptions, BugsnagUnity.Payload.HandledState handledState, System.Func`2[T,TResult] callback, System.Nullable`1[T] logType)
    <00000000000000000000000000000000> BugsnagUnity.Client+<>c__DisplayClass56_0.<Notify>b__0()
    <00000000000000000000000000000000> BugsnagUnity.MainThreadDispatchBehaviour+<ActionWrapper>d__6.MoveNext()
    <00000000000000000000000000000000> UnityEngine.SetupCoroutine.InvokeMoveNext(System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
    <00000000000000000000000000000000> BugsnagUnity.MainThreadDispatchBehaviour.Update()
InvalidOperationException Collection was modified; enumeration operation may not execute. 
    <00000000000000000000000000000000> System.Collections.Generic.List`1+Enumerator[T].MoveNextRare()
    <00000000000000000000000000000000> System.Collections.Generic.List`1+Enumerator[T].MoveNext()
    <00000000000000000000000000000000> BugsnagUnity.Client.NotifyOnMainThread(BugsnagUnity.Payload.Error[] exceptions, BugsnagUnity.Payload.HandledState handledState, System.Func`2[T,TResult] callback, System.Nullable`1[T] logType)
    <00000000000000000000000000000000> BugsnagUnity.MainThreadDispatchBehaviour+<ActionWrapper>d__6.MoveNext()
    <00000000000000000000000000000000> UnityEngine.SetupCoroutine.InvokeMoveNext(System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
    <00000000000000000000000000000000> BugsnagUnity.MainThreadDispatchBehaviour.Update()

gagbaghdas avatar Apr 01 '24 16:04 gagbaghdas

It seems it is being thrown when the notify is being called from different threads. Any thoughts?

gagbaghdas avatar Apr 02 '24 22:04 gagbaghdas

Hi @gagbaghdas

Can you please share a copy of your BugSnag configuration and callback configurations, including any code snippets or screenshots that may aid in our investigation?

clr182 avatar Apr 05 '24 11:04 clr182

@clr182 sure. Here is my code:

using System;
using System.Collections.Generic;
using BugsnagUnity;

namespace MyNameSpace
{
    public class BugsnagWrapper : MyInterface
    {
        private const string bugsangApiKey = "MySDKKey";
        private bool initialized = false;
        private bool userInitialized = false;
        private ErrorReportingUserMainProperties userProperties;
        private readonly Dictionary<string, object> customProperties = new();

        public void Initialize(IContext context)
        {
            // Call this method if you don't want Bugsnag to be started automatically before first scene load

            //InitializeBugsangManully();
        }

        /// <summary>
        /// Starts Bugsnag Service manually
        /// </summary>
        private void InitializeBugsangManully()
        {
            if (!initialized)
            {
                var config = BugsnagSettingsObject.LoadConfiguration();

                config.ApiKey = bugsangApiKey;

                Bugsnag.Start(config);
                initialized = true;
            }
        }

        public void InitializeUser(ErrorReportingUserMainProperties userProperties)
        {
            if (userInitialized)
            {
                return;
            }
            this.userProperties = userProperties;

            Bugsnag.SetUser(userProperties.UserId, string.Empty, string.Empty);
            AddMetadata("user", userProperties.GetPropertiesDictionary());
            userInitialized = true;
        }

        public void Notify(Exception ex)
        {
            bool BeforeNotify(BugsnagUnity.IEvent @event)
            {
                if(userProperties != null)
                {
                    if (!string.IsNullOrEmpty(userProperties.UserId) && @event.GetUser().Id != userProperties.UserId)
                    {
                        Bugsnag.SetUser(userProperties.UserId, string.Empty, string.Empty);
                    }

                    AddMetadata("user", userProperties.GetPropertiesDictionary());
                }

                AddMetadata("customProperties", customProperties);

                return true;

            }

            Bugsnag.AddOnError(BeforeNotify);
            Bugsnag.Notify(ex);
            Bugsnag.RemoveOnError(BeforeNotify);
        }

        private void AddMetadata(string section, Dictionary<string, object> addingMetadata)
        {
            if (addingMetadata.Count == 0)
            {
                return;
            }

            if (Bugsnag.GetMetadata(section) == null || Bugsnag.GetMetadata(section).Count == 0)
            {
                Bugsnag.AddMetadata(section, addingMetadata);
                return;
            }

            foreach (var metaData in addingMetadata)
            {
                if (Bugsnag.GetMetadata(section, metaData.Key) == null)
                {
                    Bugsnag.AddMetadata(section, metaData.Key, metaData.Value);
                    continue;
                }

                if (Bugsnag.GetMetadata(section, metaData.Key) != metaData.Value)
                {
                    Bugsnag.ClearMetadata(section, metaData.Key);
                    Bugsnag.AddMetadata(section, metaData.Key, metaData.Value);
                }
            }
        }

        public void Restart()
        {
            initialized = false;
        }

        public void SetCustomProperty(string key, string value)
        {
            customProperties[key] = value;
        }
    }
}

And here is the configuration:

Screenshot 2024-04-19 at 19 46 15

Thanks

gagbaghdas avatar Apr 19 '24 15:04 gagbaghdas