stride3d/stride · error · InvalidOperationException

Input Source already added

Error message

Input Source already added

What it means

When the Sources tracking collection changes, the InputManager validates each Add and throws InvalidOperationException if the same IInputSource instance is already present (duplicated via Count > 1). Each source may only be initialized and subscribed once.

Solutions

  1. Add the source only once; guard with Sources.Contains(source) before Add.
  2. Move source registration out of code that may re-execute (OnSceneLoad, Initialize).
  3. Create a new IInputSource instance instead of re-adding a used one.

Example fix

// before
Sources.Add(mySource); // may run twice
// after
if (!Sources.Contains(mySource)) Sources.Add(mySource);
Defensive patterns

Strategy: validation

Validate before calling

if (!input.Sources.Contains(source)) input.Sources.Add(source);

Try / catch

try { input.Sources.Add(source); }
catch (InvalidOperationException ex) when (ex.Message == "Input Source already added") { /* already registered: ignore */ }

Prevention

When it happens

Trigger: Adding the same IInputSource instance to InputManager.Sources twice, e.g. calling Sources.Add(source) in code that runs again on scene reload or when Initialize is invoked twice.

Common situations: Game initialization re-run after reload; copy-pasted setup code adding a source in two places; sharing one source instance across multiple InputManagers.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/cac309bf3e111fe0. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Input/InputManager.cs:597

        /// <summary>
        /// Resume all input sources.
        /// </summary>
        public void Resume()
        {
            foreach (var source in Sources)
            {
                source.Resume();
            }
        }

        private void SourcesOnCollectionChanged(object o, TrackingCollectionChangedEventArgs e)
        {
            var source = (IInputSource)e.Item;
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (Sources.Count(x => x == source) > 1)
                        throw new InvalidOperationException("Input Source already added");

                    EventHandler<TrackingCollectionChangedEventArgs> eventHandler = (sender, args) => InputDevicesOnCollectionChanged(source, args);
                    devicesCollectionChangedActions.Add(source, eventHandler);
                    source.Devices.CollectionChanged += eventHandler;
                    source.Initialize(this);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    source.Dispose();
                    source.Devices.CollectionChanged -= devicesCollectionChangedActions[source];
                    devicesCollectionChangedActions.Remove(source);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(e.Action));
            }
        }

        /// <summary>
        /// Registers an input event type to process

View on GitHub (pinned to 96fad776d2)