stride3d/stride · error · InvalidOperationException

Something should handle controller disconnect

Error message

Something should handle controller disconnect

What it means

GamePadXInput.Dispose uses Disconnected == null as a guard: if nobody subscribed to the Disconnected event, disposing the gamepad would orphan it, so Dispose throws InvalidOperationException with 'Something should handle controller disconnect'. It is an invariant enforcing that disconnect handling is wired before a device is torn down.

Solutions

  1. Use InputSourceWindowsXInput.OpenDevice to create gamepads so the Disconnected handler is attached automatically.
  2. Subscribe to Disconnected before disposing the gamepad.
  3. Dispose gamepads through the input source rather than calling Dispose directly.

Example fix

// before
gamePad.Dispose();
// after
gamePad.Disconnected += (s, e) => { /* remove device */ };
gamePad.Dispose();
Defensive patterns

Strategy: validation

Validate before calling

if (gamePad.Disconnected == null)
    throw new InvalidOperationException("Attach a Disconnected handler before disposing the XInput gamepad.");
gamePad.Dispose();

Type guard

bool SafeToDispose(GamePadXInput g) => g.Disconnected != null;

Try / catch

try
{
    gamePad.Dispose();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("controller disconnect"))
{
    // Subscribe to Disconnected and retry disposal via the input source.
}

Prevention

When it happens

Trigger: Calling DisconnectAndDispose (or Dispose directly) on a GamePadXInput whose Disconnected event has no subscribers.

Common situations: Manually creating and disposing GamePadXInput instances outside InputSourceWindowsXInput; app shutdown ordering that disposes gamepads after the input source cleared its handlers.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Input/Windows/GamePadXInput.cs:50

            // Used to create a product ID that matches SDL2's method of generating them
            // Taken from SDL 2.0.5 (src\joystick\windows\SDL_xinputjoystick.c:149)
            var subType = controller.GetCapabilities(DeviceQueryType.Any).SubType;
            var pidBytes = Encoding.ASCII.GetBytes("xinput").ToList();
            pidBytes.Add((byte)subType);

            while (pidBytes.Count < 16)
            {
                pidBytes.Add(0);
            }

            ProductId = new Guid(pidBytes.ToArray());
        }

        public void Dispose()
        {
            if (Disconnected == null)
                throw new InvalidOperationException("Something should handle controller disconnect");
        }

        public override string Name => $"XInput GamePad {Index}";
        public override Guid Id { get; }
        public override Guid ProductId { get; }
        public override GamePadState State => state;
        public override IInputSource Source { get; }

        public event EventHandler Disconnected;

        public override void Update(List<InputEvent> inputEvents)
        {
            if ((int)controller.UserIndex != Index)
            {
                SetIndexInternal((int)controller.UserIndex);
            }

            ClearButtonStates();

View on GitHub (pinned to 96fad776d2)