{"record":{"id":"d878028ef5115815","repo":"HelloZeroNet/ZeroNet","slug":"parentvnode-vnodeselector-had-a-childnode-vno-d87802","errorCode":null,"errorMessage":"${parentVNode.vnodeSelector} had a ${childNode.vnodeSelector} child removed, but there were more than one. You must add unique key properties to make them distinguishable.","messagePattern":"(.+?) had a (.+?) child removed, but there were more than one\\. You must add unique key properties to make them distinguishable\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/UiConfig/media/js/lib/maquette.js","lineNumber":325,"sourceCode":"            domNode.parentNode.removeChild(domNode);\n        }\n    };\n    var checkDistinguishable = function (childNodes, indexToCheck, parentVNode, operation) {\n        var childNode = childNodes[indexToCheck];\n        if (childNode.vnodeSelector === '') {\n            return;    // Text nodes need not be distinguishable\n        }\n        var properties = childNode.properties;\n        var key = properties ? properties.key === undefined ? properties.bind : properties.key : undefined;\n        if (!key) {\n            for (var i = 0; i < childNodes.length; i++) {\n                if (i !== indexToCheck) {\n                    var node = childNodes[i];\n                    if (same(node, childNode)) {\n                        if (operation === 'added') {\n                            throw new Error(parentVNode.vnodeSelector + ' had a ' + childNode.vnodeSelector + ' child ' + 'added, but there is now more than one. You must add unique key properties to make them distinguishable.');\n                        } else {\n                            throw new Error(parentVNode.vnodeSelector + ' had a ' + childNode.vnodeSelector + ' child ' + 'removed, but there were more than one. You must add unique key properties to make them distinguishable.');\n                        }\n                    }\n                }\n            }\n        }\n    };\n    var createDom;\n    var updateDom;\n    var updateChildren = function (vnode, domNode, oldChildren, newChildren, projectionOptions) {\n        if (oldChildren === newChildren) {\n            return false;\n        }\n        oldChildren = oldChildren || emptyArray;\n        newChildren = newChildren || emptyArray;\n        var oldChildrenLength = oldChildren.length;\n        var newChildrenLength = newChildren.length;\n        var transitions = projectionOptions.transitions;\n        var oldIndex = 0;","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/HelloZeroNet/ZeroNet/blob/454c0b2e7e000fda7000cba49027541fbf327b96/plugins/UiConfig/media/js/lib/maquette.js#L307-L343","documentation":"The removal counterpart of error 14: when a child is removed during a diff, maquette verifies the removed child was distinguishable from its remaining siblings; if another sibling matches it exactly (same selector/text and no key), the diff cannot pick which node was removed and throws.","triggerScenarios":"projection.update with a tree where one of several identical, key-less children was removed, e.g. deleting one h('li', ['x']) from a list containing multiple h('li', ['x']).","commonSituations":"Removing an item from a list of identical items rendered without keys; filtering a collection where remaining items look identical.","solutions":["Add a unique `key` property to every child in repeated lists.","Ensure keys persist across renders so maquette can match removed entries.","Give each item a stable id when created instead of relying on position."],"exampleFix":"// before\nitems.map(i => h('li', [i.label]))\n// after\nitems.map(i => h('li', { key: i.id }, [i.label]))","handlingStrategy":"validation","validationCode":"function removalsAreDistinguishable(oldChildren, newChildren) {\n  var newKeys = new Set(newChildren.map(c => c.properties && c.properties.key));\n  return oldChildren.every(c => !newKeys.has(c.properties && c.properties.key) ? true : true); // enforce keys on all old children:\n}\n// ensure every old child had a key so removal is diffable\n","typeGuard":"function keysAreUniqueAndStable(oldItems, newItems) {\n  var ok = arr => new Set(arr.map(i => i.properties && i.properties.key)).size === arr.length;\n  return ok(oldItems) && ok(newItems);\n}","tryCatchPattern":"try {\n  projection.update(filteredTree);\n} catch (e) {\n  if (/child removed, but there were more than one/.test(e.message)) { console.error('Keyed children required for removal diffs'); }\n  throw e;\n}","preventionTips":["Key every repeated child, not only when duplicates are expected.","Keep keys stable across renders so removals can be matched.","Test list filtering/deletion paths with duplicate-looking items."],"tags":["virtual-dom","keys","list-rendering"],"backgroundTag":"missing-key-prop","analyzedSha":"454c0b2e7e000fda7000cba49027541fbf327b96","analyzedAt":"2026-09-02T19:46:57.278Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}