stride3d/stride · error · InvalidOperationException
Something should handle controller disconnect
Error message
Something should handle controller disconnect
What it means
GameControllerSDL.Dispose closes the SDL joystick and then invokes the Disconnected event; if no handler is attached (Disconnected == null), it throws, because the source would never learn the controller went away and would keep a dangling device. The library mandates that someone must handle controller disconnect before a controller is disposed.
Solutions
- Ensure InputSourceSDL (or your owning code) subscribes to controller.Disconnected before any Dispose can occur
- Do not dispose a controller without a Disconnected handler in place
- In custom code, attach a no-op or logging handler if you don't need disconnect logic: controller.Disconnected += (s,e) => {};
- If this fires during shutdown, unregister the device from the source before disposing
Example fix
// before
controller.Dispose(); // Disconnected == null -> throws
// after
controller.Disconnected += (sender, args) => { /* handle removal */ };
controller.Dispose(); Defensive patterns
Strategy: validation
Validate before calling
controller.Disconnected += OnControllerDisconnected; controller.Dispose();
Try / catch
try { controller.Dispose(); } catch (InvalidOperationException ex) { log.Warn($"Controller {controller.Id} disposed without disconnect handler"); } Prevention
- Subscribe to Disconnected immediately after a controller is created/opened
- Never unsubscribe Disconnected before disposal
- Use a no-op handler if your app has no disconnect logic
When it happens
Trigger: Disposing a GameControllerSDL while its Disconnected event has no subscribers — typically when the source removed its event handler, or the controller object is disposed before being wired to the source's handling code.
Common situations: SDL joystick hot-unplug triggering source-side cleanup that disposes the controller before re-subscribing; user code creating GameControllerSDL instances directly in tests without attaching Disconnected; refactors that accidentally unsubscribe the handler first.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- SDL GameController already opened
- This GamePad's index can not be changed
- Not a valid gamepad
- Gamepad index was out of range
- Can not set more than one button at a time
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/ff5ba193b2dfed15.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Input/SDL/GameControllerSDL.cs:78
public override Guid ProductId { get; }
public override IInputSource Source { get; }
public override IReadOnlyList<GameControllerButtonInfo> ButtonInfos => buttonInfos;
public override IReadOnlyList<GameControllerAxisInfo> AxisInfos => axisInfos;
public override IReadOnlyList<GameControllerDirectionInfo> DirectionInfos => povControllerInfos;
public event EventHandler Disconnected;
public void Dispose()
{
if (!disposed)
{
SDL.JoystickClose(joystick);
if (Disconnected == null)
throw new InvalidOperationException("Something should handle controller disconnect");
Disconnected.Invoke(this, null);
disposed = true;
}
}
public override void Update(List<InputEvent> inputEvents)
{
if (SDL.JoystickGetAttached(joystick) == SdlBool.False)
{
Dispose();
return;
}
for (int i = 0; i < buttonInfos.Count; i++)
{
HandleButton(i, SDL.JoystickGetButton(joystick, i) != 0);
}
View on GitHub (pinned to 96fad776d2)