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
- Use InputSourceWindowsXInput.OpenDevice to create gamepads so the Disconnected handler is attached automatically.
- Subscribe to Disconnected before disposing the gamepad.
- 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
- Create XInput gamepads only via InputSourceWindowsXInput.OpenDevice, which wires the handler.
- Never call Dispose directly on GamePadXInput from game code.
- Order shutdown so the input source disposes its devices.
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
- Invalid XInput device index
- XInput device already opened
- DirectInput GameController already opened
- Something should handle controller disconnect
- Something should handle controller disconnect
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)