{"record":{"id":"e9d5b68a20ade3d8","repo":"plotly/plotly.js","slug":"index-out-of-range","errorCode":null,"errorMessage":"index out of range","messagePattern":"index out of range","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/plot_api/manage_arrays.js","lineNumber":128,"sourceCode":"    var maxIndex = componentArray.length;\n    var i;\n    var j;\n    var componentNum;\n    var objEdits;\n    var objKeys;\n    var objVal;\n    var adding, prefix;\n\n    // first make the add and edit changes\n    for(i = 0; i < componentNums.length; i++) {\n        componentNum = componentNums[i];\n        objEdits = edits[componentNum];\n        objKeys = Object.keys(objEdits);\n        objVal = objEdits[''],\n        adding = isAddVal(objVal);\n\n        if(componentNum < 0 || componentNum > componentArray.length - (adding ? 0 : 1)) {\n            Loggers.warn('index out of range', componentType, componentNum);\n            continue;\n        }\n\n        if(objVal !== undefined) {\n            if(objKeys.length > 1) {\n                Loggers.warn(\n                    'Insertion & removal are incompatible with edits to the same index.',\n                    componentType, componentNum);\n            }\n\n            if(isRemoveVal(objVal)) {\n                deletes.push(componentNum);\n            } else if(adding) {\n                if(objVal === 'add') objVal = {};\n                componentArray.splice(componentNum, 0, objVal);\n                if(componentArrayFull) componentArrayFull.splice(componentNum, 0, {});\n            } else {\n                Loggers.warn('Unrecognized full object edit value',","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/plotly/plotly.js/blob/1d090e0b5ffb8d0fdf6e0e4ff51d3f3cf67f1314/src/plot_api/manage_arrays.js#L110-L146","documentation":"For per-index edits to an array component (e.g. 'annotations.2' style edits), the componentNum index must point at an existing object (or, when the edit is an addition, one past the end). Out-of-range indices are reported with this warning and skipped via `continue`, leaving the array unchanged for that entry.","triggerScenarios":"Editing 'annotations[5]' when only 3 annotations exist; removing (or editing, non-adding) an index equal to array length; negative component numbers from decrement loops.","commonSituations":"React/update calls derived from stale UI state after items were deleted elsewhere, off-by-one errors (index === length), and batch edits computed against a previous array snapshot.","solutions":["Check the current array length (gd.layout[componentType].length) and clamp/skip the index before the edit.","Use the 'adding' form (value = new object) when you actually want to append at index === length.","Re-read the layout array before batch edits instead of using cached lengths.","Verify index arithmetic for loops (i < arr.length, i >= 0)."],"exampleFix":"// before\nedits[idx] = { text: 'x' }; // idx may exceed array length\n// after\nif (idx >= 0 && idx < gd.layout.annotations.length) {\n  edits[idx] = { text: 'x' };\n}","handlingStrategy":"validation","validationCode":"function assertIndexInRange(gd, componentType, num, adding) {\n  const arr = gd.layout[componentType] || [];\n  if (num < 0 || num > arr.length - (adding ? 0 : 1)) {\n    throw new RangeError(`${componentType} index ${num} out of range (len ${arr.length})`);\n  }\n}","typeGuard":"function inRange(num, len, adding) { return Number.isInteger(num) && num >= 0 && num <= len - (adding ? 0 : 1); }","tryCatchPattern":null,"preventionTips":["Read gd.layout[componentType].length before computing per-index edits.","Use the add form when appending at index === length.","Recompute indices after any deletion; never reuse stale snapshots."],"tags":["relayout","index-out-of-bounds","array-edits"],"backgroundTag":"index-out-of-range","analyzedSha":"1d090e0b5ffb8d0fdf6e0e4ff51d3f3cf67f1314","analyzedAt":"2026-09-02T22:03:39.906Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}