{"record":{"id":"1d08936d9896c4eb","repo":"plotly/plotly.js","slug":"relayout-fail","errorCode":null,"errorMessage":"Relayout fail.","messagePattern":"Relayout fail\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/plot_api/plot_api.js","lineNumber":1708,"sourceCode":" *\n * Signature 2:\n * @param {String | HTMLDivElement} gd\n *  (as in signature 1)\n * @param {Object} aobj\n *  attribute object `{astr1: val1, astr2: val2 ...}`\n *  allows setting multiple attributes simultaneously\n */\nfunction relayout(gd, astr, val) {\n    gd = Lib.getGraphDiv(gd);\n    helpers.clearPromiseQueue(gd);\n\n    var aobj = {};\n    if (typeof astr === 'string') {\n        aobj[astr] = val;\n    } else if (Lib.isPlainObject(astr)) {\n        aobj = Lib.extendFlat({}, astr);\n    } else {\n        Lib.warn('Relayout fail.', astr, val);\n        return Promise.reject();\n    }\n\n    if (Object.keys(aobj).length) gd.changed = true;\n\n    var specs = _relayout(gd, aobj);\n    var flags = specs.flags;\n\n    // clear calcdata if required\n    if (flags.calc) gd.calcdata = undefined;\n\n    // fill in redraw sequence\n\n    // even if we don't have anything left in aobj,\n    // something may have happened within relayout that we\n    // need to wait for\n    var seq = [Plots.previousPromises];\n    if (flags.layoutReplot) {","sourceCodeStart":1690,"sourceCodeEnd":1726,"githubUrl":"https://github.com/plotly/plotly.js/blob/1d090e0b5ffb8d0fdf6e0e4ff51d3f3cf67f1314/src/plot_api/plot_api.js#L1690-L1726","documentation":"Plotly.relayout requires its astr argument to be an attribute string ('xaxis.range[0]') or a plain object of attribute/value pairs. Any other type cannot form the update object, so relayout logs 'Relayout fail.' and returns a rejected promise; the layout is left unchanged.","triggerScenarios":"Plotly.relayout(gd, 123), Plotly.relayout(gd, undefined), Plotly.relayout(gd, someArray), or forwarding a non-object payload (e.g. JSON string, DOM event) as the update spec.","commonSituations":"Parsing layout updates from a server and forgetting JSON.parse; passing React state objects that are actually arrays; calling relayout with only (gd) in an event handler whose args shifted after a plotly.js major-version upgrade; wrapper libraries misfwding arguments.","solutions":["Pass a string path with a value: Plotly.relayout(gd, 'xaxis.range[0]', 5)","Or pass a plain object: Plotly.relayout(gd, {'xaxis.range': [0, 10]})","Guard before calling: if (typeof astr !== 'string' && !Lib-like isPlainObject(astr)) return","JSON.parse server-supplied update specs before passing them","Chain .catch on the returned promise to detect and log the bad call site"],"exampleFix":"// before\nPlotly.relayout(gd, JSON.stringify({'yaxis.range': [0, 5]}));\n// after\nPlotly.relayout(gd, JSON.parse(jsonSpec));","handlingStrategy":"type-guard","validationCode":"function canRelayout(astr) {\n  if (typeof astr === 'string' && astr.length) return true;\n  return astr !== null && typeof astr === 'object' && !Array.isArray(astr);\n}\nif (!canRelayout(spec)) throw new TypeError('relayout spec must be a string or plain object');","typeGuard":"function isPlainObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }\nfunction isRelayoutSpec(v) { return (typeof v === 'string' && v.length > 0) || isPlainObject(v); }","tryCatchPattern":"Plotly.relayout(gd, astr, val).catch(err => console.error('relayout failed for', astr, err));","preventionTips":["Parse JSON strings into objects before passing layout updates","Never pass arrays, numbers, or undefined as the relayout spec","Validate specs coming from servers or templates","Keep relayout argument order (gd, astr, val) intact in wrappers"],"tags":["api-misuse","relayout","type-error"],"backgroundTag":"invalid-update-value","analyzedSha":"1d090e0b5ffb8d0fdf6e0e4ff51d3f3cf67f1314","analyzedAt":"2026-09-02T22:03:39.906Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}