{"record":{"id":"7cc09abf7a64d2ed","repo":"plotly/plotly.js","slug":"addframes-overwriting-frame-name-with-a-fram","errorCode":null,"errorMessage":"addFrames: overwriting frame \"${name}\" with a frame whose name of type \"number\" also equates to \"${name}\". This is valid but may potentially lead to unexpected behavior since all plotly.js frame names are stored internally as strings.","messagePattern":"addFrames: overwriting frame \"(.+?)\" with a frame whose name of type \"number\" also equates to \"(.+?)\"\\. This is valid but may potentially lead to unexpected behavior since all plotly\\.js frame names are stored internally as strings\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/plot_api/plot_api.js","lineNumber":3460,"sourceCode":"        if (!Lib.isPlainObject(frameList[i])) continue;\n\n        // The entire logic for checking for this type of name collision can be removed once we migrate to ES6 and\n        // use a Map instead of an Object instance, as Map keys aren't converted to strings.\n        var lookupName = frameList[i].name;\n        var name = (_frameHash[lookupName] || _frameHashLocal[lookupName] || {}).name;\n        var newName = frameList[i].name;\n        var collisionPresent = _frameHash[name] || _frameHashLocal[name];\n\n        if (\n            name &&\n            newName &&\n            typeof newName === 'number' &&\n            collisionPresent &&\n            numericNameWarningCount < numericNameWarningCountLimit\n        ) {\n            numericNameWarningCount++;\n\n            Lib.warn(\n                'addFrames: overwriting frame \"' +\n                    (_frameHash[name] || _frameHashLocal[name]).name +\n                    '\" with a frame whose name of type \"number\" also equates to \"' +\n                    name +\n                    '\". This is valid but may potentially lead to unexpected ' +\n                    'behavior since all plotly.js frame names are stored internally ' +\n                    'as strings.'\n            );\n\n            if (numericNameWarningCount === numericNameWarningCountLimit) {\n                Lib.warn(\n                    'addFrames: This API call has yielded too many of these warnings. ' +\n                        'For the rest of this call, further warnings about numeric frame ' +\n                        'names will be suppressed.'\n                );\n            }\n        }\n","sourceCodeStart":3442,"sourceCodeEnd":3478,"githubUrl":"https://github.com/plotly/plotly.js/blob/1d090e0b5ffb8d0fdf6e0e4ff51d3f3cf67f1314/src/plot_api/plot_api.js#L3442-L3478","documentation":"Plotly.addFrames stores all frame names internally as strings. Adding a frame whose name is a JavaScript number that stringifies to an already-registered name (e.g. numeric 0 vs string '0') silently overwrites the existing frame. Plotly warns that this is valid but can cause unexpected behavior. The warning is throttled per call via numericNameWarningCount.","triggerScenarios":"Plotly.addFrames(gd, [{name: 0}, ...]) with typeof name === 'number' where String(name) collides with an existing frame name in _frameHash or _frameHashLocal, and fewer than numericNameWarningCountLimit such warnings have been emitted for this call.","commonSituations":"Generating frames in a loop with numeric indices as names while other code registered string names; mixing frame definitions from JSON (string names) with programmatic frames (number names); mapping dataset indices directly to frame names.","solutions":["Coerce frame names to strings when creating frames (String(i) or template literals) so types match the internal string registry.","Use unique prefixed names (e.g. 'frame-0') to eliminate coercion collisions entirely.","If the overwrite is intentional, restructure the naming so it is explicit rather than an accident of coercion."],"exampleFix":"// before\nPlotly.addFrames(gd, frames.map((f, i) => ({name: i, data: f})));\n// after\nPlotly.addFrames(gd, frames.map((f, i) => ({name: String(i), data: f})));","handlingStrategy":"validation","validationCode":"function assertStringFrameNames(frames) {\n  const bad = frames.filter(f => typeof f.name === 'number');\n  if (bad.length) {\n    throw new TypeError('Frame names must be strings: ' + bad.map(f => f.name).join(', '));\n  }\n}\n// usage: assertStringFrameNames(frames); Plotly.addFrames(gd, frames);","typeGuard":"function hasStringName(frame) {\n  return frame != null && typeof frame.name === 'string' && frame.name.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Always construct frame names with String(i) or a prefix.","Never pass raw numeric indices as frame names.","Use unique descriptive names to avoid silent overwrites.","Audit frame sources (JSON vs code) for mixed name types."],"tags":["plotly","addframes","frame-names","type-coercion","naming-collision"],"backgroundTag":"numeric-frame-name-collision","analyzedSha":"1d090e0b5ffb8d0fdf6e0e4ff51d3f3cf67f1314","analyzedAt":"2026-09-02T22:03:39.906Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}