plotly/plotly.js · warning

unrecognized full object value

Error message

unrecognized full object value

What it means

During _relayout processing of whole-object updates to container arrays (e.g. 'annotations[2]' set to a single value), the value must be an add value ('add' or plain object) or a remove value (null/[0]) for plotly.js to compute an undo entry. Any other value is unrecognized: the change is not undone correctly and this warning is logged.

Source

Thrown at src/plot_api/plot_api.js:2089

        // and order-independence for add/remove/edit all together in
        // one relayout call
        var containerArrayMatch = manageArrays.containerArrayMatch(ai);
        if (containerArrayMatch) {
            arrayStr = containerArrayMatch.array;
            i = containerArrayMatch.index;
            var propStr = containerArrayMatch.property;
            var updateValObject = valObject || { editType: 'calc' };

            if (i !== '' && propStr === '') {
                // special handling of undoit if we're adding or removing an element
                // ie 'annotations[2]' which can be {...} (add) or null,
                // does not work when replacing the entire array
                if (manageArrays.isAddVal(vi)) {
                    undoit[ai] = null;
                } else if (manageArrays.isRemoveVal(vi)) {
                    undoit[ai] = (nestedProperty(layout, arrayStr).get() || [])[i];
                } else {
                    Lib.warn('unrecognized full object value', aobj);
                }
            }
            editTypes.update(flags, updateValObject);

            // prepare the edits object we'll send to applyContainerArrayChanges
            if (!arrayEdits[arrayStr]) arrayEdits[arrayStr] = {};
            var objEdits = arrayEdits[arrayStr][i];
            if (!objEdits) objEdits = arrayEdits[arrayStr][i] = {};
            objEdits[propStr] = vi;

            delete aobj[ai];
        } else if (pleaf === 'reverse') {
            // handle axis reversal explicitly, as there's no 'reverse' attribute

            if (parentIn.range) parentIn.range.reverse();
            else {
                doextra(ptrunk + '.autorange', true);
                parentIn.range = [1, 0];

View on GitHub (pinned to 1d090e0b5f)

Solutions

  1. Assign a plain object to replace the item: Plotly.relayout(gd, 'annotations[2]', {x: 1, y: 2})
  2. Use 'add' to insert at that index: Plotly.relayout(gd, 'annotations[2]', 'add')
  3. Use null (or [0]) to remove: Plotly.relayout(gd, 'annotations[2]', null)
  4. Validate each value in the aobj with manageArrays.isAddVal/isRemoveVal-equivalent checks before calling relayout
  5. For wholesale array replacement set the whole array instead of per-index: Plotly.relayout(gd, 'annotations', newArray)

Example fix

// before
Plotly.relayout(gd, 'annotations[1]', 'remove');
// after
Plotly.relayout(gd, 'annotations[1]', null);
Defensive patterns

Strategy: validation

Validate before calling

function isValidContainerIndexValue(v) {
  return v === 'add' || v === null || (v && typeof v === 'object' && !Array.isArray(v));
}
for (const [k, v] of Object.entries(spec)) {
  if (/\[\d+\]$/.test(k) && !isValidContainerIndexValue(v)) throw new TypeError(k + ' needs object, \'add\', or null');
}

Type guard

function isPlainObj(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }
const isAddVal = v => v === 'add' || isPlainObj(v);
const isRemoveVal = v => v === null;

Try / catch

try { await Plotly.relayout(gd, spec); } catch (e) { console.error('relayout with container index value rejected', spec, e); }

Prevention

When it happens

Trigger: Plotly.relayout(gd, 'annotations[2]', 'foo') or Plotly.relayout(gd, {'shapes[0]': 5}) - assigning a primitive/string to a full container index rather than an object, 'add', or null. Also storing removal sentinels as strings like 'remove' instead of null.

Common situations: Template-driven relayouts where a placeholder string was not substituted; diff libraries emitting primitives for removed entries; code written against an imagined 'remove'/'delete' keyword that plotly.js never supported; type coercion after JSON round-trips turning null into 'null'.

Related errors


AI-assisted analysis of plotly/plotly.js@1d090e0b5f (2026-09-02). Data as JSON: /api/errors/49cd714088d42018. Report an issue: GitHub.