{"record":{"id":"2d8780f60dcd0bad","repo":"stride3d/stride","slug":"gamepad-index-was-out-of-range","errorCode":null,"errorMessage":"Gamepad index was out of range","messagePattern":"Gamepad index was out of range","errorType":"validation","errorClass":"IndexOutOfRangeException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Input/InputManager.cs","lineNumber":931,"sourceCode":"            gamePads.Add(gamePad);\n\n            // Check if the gamepad provides an interface for assigning gamepad index\n            if (gamePad.CanChangeIndex)\n            {\n                gamePad.Index = GetFreeGamePadIndex(gamePad);\n            }\n            \n            // Handle later index changed\n            gamePad.IndexChanged += GamePadOnIndexChanged;\n            UpdateGamePadRequestedIndices();\n        }\n\n        private void UnregisterGamePad(IGamePadDevice gamePad)\n        {\n            // Free the gamepad index in the gamepad list\n            // this will allow another gamepad to use this index again\n            if (gamePadRequestedIndex.Count <= gamePad.Index || gamePad.Index < 0)\n                throw new IndexOutOfRangeException(\"Gamepad index was out of range\");\n\n            gamePadRequestedIndex[gamePad.Index].Remove(gamePad);\n\n            gamePads.Remove(gamePad);\n            gamePad.IndexChanged -= GamePadOnIndexChanged;\n        }\n\n        private void RegisterGameController(IGameControllerDevice gameController)\n        {\n            gameControllers.Add(gameController);\n        }\n\n        private void UnregisterGameController(IGameControllerDevice gameController)\n        {\n            gameControllers.Remove(gameController);\n        }\n\n        private void GamePadOnIndexChanged(object sender, GamePadIndexChangedEventArgs e)","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Input/InputManager.cs#L913-L949","documentation":"UnregisterGamePad frees the gamepad's slot in gamePadRequestedIndex. If gamePad.Index is negative or >= gamePadRequestedIndex.Count, the internal index table no longer matches the device and Stride throws IndexOutOfRangeException as an invariant failure rather than silently corrupting state.","triggerScenarios":"A gamepad with an out-of-sync Index (never allocated, or table shrunk) being unregistered; double-unregister of the same gamepad after its index was invalidated.","commonSituations":"Rapid connect/disconnect of controllers where a device is torn down twice; custom platform backends assigning Index without going through GetFreeGamePadIndex; shutdown ordering issues.","solutions":["Allocate indices only via InputManager.GetFreeGamePadIndex so Index stays in sync.","Ensure each gamepad is unregistered exactly once (guard custom teardown code).","Update Stride if the crash occurs during normal hot-plug with official backends."],"exampleFix":"// before\ngamePad.Index = 0; // hand-assigned, out of sync with table\n// after\nvar idx = inputManager.GetFreeGamePadIndex(gamePad);\ngamePad.RequestedIndex = idx;","handlingStrategy":"try-catch","validationCode":"bool IndexValid(IGamePadDevice pad, int requestedIndexCount) => pad.Index >= 0 && pad.Index < requestedIndexCount;","typeGuard":null,"tryCatchPattern":"try { /* unregister path runs internally */ }\ncatch (IndexOutOfRangeException ex) when (ex.Message == \"Gamepad index was out of range\")\n{ logger.Warn(ex, \"Stale gamepad index; forcing device list refresh\"); }","preventionTips":["Assign indices only through GetFreeGamePadIndex.","Unregister each gamepad exactly once.","Keep Stride platform backends up to date for hot-plug fixes."],"tags":["input","gamepad","index-out-of-range"],"backgroundTag":"index-out-of-range","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}