{"record":{"id":"5a133b7b8a6b7e5b","repo":"angular/components","slug":"cdkstepper-cannot-assign-out-of-bounds-value-to","errorCode":null,"errorMessage":"cdkStepper: Cannot assign out-of-bounds value to `selectedIndex`.","messagePattern":"cdkStepper: Cannot assign out-of-bounds value to `selectedIndex`\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cdk/stepper/stepper.ts","lineNumber":362,"sourceCode":"  @Input({transform: booleanAttribute})\n  get linear(): boolean {\n    return this._linear();\n  }\n  set linear(value: boolean) {\n    this._linear.set(value);\n  }\n  private _linear = signal(false);\n\n  /** The index of the selected step. */\n  @Input({transform: numberAttribute})\n  get selectedIndex(): number {\n    return this._selectedIndex();\n  }\n  set selectedIndex(index: number) {\n    if (this._steps) {\n      // Ensure that the index can't be out of bounds.\n      if (!this._isValidIndex(index) && (typeof ngDevMode === 'undefined' || ngDevMode)) {\n        throw Error('cdkStepper: Cannot assign out-of-bounds value to `selectedIndex`.');\n      }\n\n      if (this.selectedIndex !== index) {\n        this.selected?._markAsInteracted();\n\n        if (\n          !this._anyControlsInvalidOrPending(index) &&\n          (index >= this.selectedIndex || this.steps.toArray()[index].editable)\n        ) {\n          this._updateSelectedItemIndex(index);\n        }\n      }\n    } else {\n      this._selectedIndex.set(index);\n    }\n  }\n  private _selectedIndex = signal(0);\n","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/stepper/stepper.ts#L344-L380","documentation":"The CdkStepper's selectedIndex setter validates that the assigned index refers to an existing step before applying it. Assigning an index below 0 or >= the number of steps throws, preventing the stepper from entering an invalid state with no selected step.","triggerScenarios":"Setting stepper.selectedIndex = n where n < 0 or n >= steps.length; assigning before steps are registered (steps query list still empty); computing an index from data that can be empty; using step.interacted/next/previous logic that derives a bad index.","commonSituations":"Restoring a selected step from a URL/route param that no longer exists; a stepper whose steps are rendered conditionally so the index is out of range at assignment time; binding [selectedIndex] to a computed value that starts at -1 before data loads.","solutions":["Clamp the index before assigning: stepper.selectedIndex = Math.min(Math.max(0, i), stepper.steps.length - 1)","Only assign after the steps are initialized (wait for afterContentInit or the steps.changes / _steps signal to be populated)","Guard against empty step lists: if (stepper.steps.length > 0) { ... }","Fix the source of the out-of-range value (route params, stored state, computed index) and validate it first"],"exampleFix":"// before\nthis.stepper.selectedIndex = this.savedStep; // may be out of bounds\n// after\nconst count = this.stepper.steps.length;\nif (count > 0) {\n  this.stepper.selectedIndex = Math.min(Math.max(0, this.savedStep), count - 1);\n}","handlingStrategy":"validation","validationCode":"const count = stepper.steps.length;\nif (index >= 0 && index < count) {\n  stepper.selectedIndex = index;\n} else {\n  console.warn(`Ignoring out-of-bounds step index ${index} (steps: ${count})`);\n}","typeGuard":"function isValidStepIndex(stepper: CdkStepper, index: number): boolean {\n  return Number.isInteger(index) && index >= 0 && index < stepper.steps.length;\n}","tryCatchPattern":"try {\n  stepper.selectedIndex = requestedIndex;\n} catch (e) {\n  if (e instanceof Error && e.message.includes('out-of-bounds')) {\n    stepper.selectedIndex = 0; // fall back to the first step\n  } else {\n    throw e;\n  }\n}","preventionTips":["Clamp stored/restored step indexes against steps.length before assigning","Wait until steps are registered (afterContentInit or steps.changes) before setting the index","Validate route/store-derived indexes before applying them","Guard against empty step lists from conditional step templates"],"tags":["angular","cdk","stepper","index-out-of-bounds","state"],"backgroundTag":"index-out-of-bounds","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}