amark/gun · error · Error
tag " " is missing hierarchy definition
Error message
tag "${name}" is missing hierarchy definition What it means
prepareOptTags validates custom options passed to $.normalize: every key in opt.tags must also appear in opt.hierarchy. The hierarchy array defines the canonical tag ordering/structure; a tag present in the tags map but absent from the hierarchy has no defined place in the normalization model, so the library refuses to proceed with this error.
Solutions
- Add every tag listed in opt.tags to the opt.hierarchy array, in the desired structural order.
- If the tag needs no special config, add it to hierarchy and let prepareOptTags auto-create tags[name] from opt.attrs.
- Fix typos so the tags key exactly matches a hierarchy entry.
- Merge from baseOpt so the default hierarchy (div, pre, ol, ul, li, h1-h6, p, a, b, code, i, span, s, sub, sup, u, br, img) is preserved and extend, not replace, it.
- Validate customOpt before passing: iterate Object.keys(opt.tags) and assert each is in opt.hierarchy.
Example fix
// before\n$.normalize(html, {tags: {section: {attrs:{}}}});\n// after\n$.normalize(html, {hierarchy: ['div','section','p','a','b','i','br','img'], tags: {section: {attrs:{}}}}); Defensive patterns
Strategy: validation
Validate before calling
function validateNormalizeOpt(opt){\n if (!Array.isArray(opt.hierarchy)) throw new Error('opt.hierarchy must be an array');\n Object.keys(opt.tags || {}).forEach(function(name){\n if (opt.hierarchy.indexOf(name) === -1)\n throw new Error('tag "'+name+'" must be added to hierarchy');\n });\n}\n// call validateNormalizeOpt(customOpt) before $.normalize(html, customOpt); Type guard
function optIsConsistent(opt){ return Array.isArray(opt.hierarchy) && !!opt.tags && Object.keys(opt.tags).every(function(n){ return opt.hierarchy.indexOf(n) !== -1; }); } Try / catch
try {\n validateNormalizeOpt(customOpt);\n $.normalize(html, customOpt);\n} catch (e) {\n if (/missing hierarchy definition/.test(e.message)) {\n console.error('Config error: add', e.message.match(/tag "([^"]+)"/)[1], 'to hierarchy');\n } else { throw e; }\n} Prevention
- Whenever you add a tags entry, add the same tag to hierarchy in the same change.
- Extend the base hierarchy rather than replacing it: $.extend(true, {}, baseOpt, customOpt).
- Watch for typos — tags keys must exactly equal hierarchy strings.
- Write a unit test that runs prepareOptTags-equivalent validation on every shipped option preset.
When it happens
Trigger: Calling $.normalize(html, customOpt) where customOpt (deep-merged over baseOpt) adds a tags entry (e.g. tags: {section: {...}}) without adding 'section' to the hierarchy array. Also triggered by typos in a tag name inside tags that don't match any hierarchy entry.
Common situations: Extending the normalizer to support new HTML tags (article, section, figure, custom elements) by only configuring tags; copying a partial customOpt example; deep-extend quirks where $.extend(true, baseOpt, customOpt) merges user tags into the base set while the user's hierarchy list omits base or new tags.
Related errors
AI-assisted analysis of amark/gun@552227599d (2026-09-02).
Data as JSON: /api/errors/b95b862ac9afc770.
Report an issue: GitHub.
Appendix: source
Thrown at lib/normalize.js:101
}
function stateMachine() {
if(unstableList.length===0)
return;
var a, i = -1;
while (a = unstableList.pop()) { // PERF: running index is probably faster than shift (mutates array)
a.unstable = false;
$(a.opt.mutate).each(function(i,fn){
return fn && fn(a, addUnstable);
});
}
}
function prepareOptTags(opt) {
var name, tag, tags = opt.tags;
for(name in tags) {
if(opt.hierarchy.indexOf(name)===-1)
throw Error('tag "'+name+'" is missing hierarchy definition');
}
opt.hierarchy.forEach(function(name){
if(!tags[name]){
tags[name] = {attrs: opt.attrs};
}
(tag=tags[name]).attrs = $.extend(tag.attrs||{}, opt.attrs);
tag.name = name; // not used, debug help (REMOVE later?)
// order
tag.order = opt.hierarchy.indexOf(name)
if(tag.order === -1) {
throw Error("Order of '"+name+"' not defined in hierarchy");
}
});
return opt;
}
// GENERAL UTILS
View on GitHub (pinned to 552227599d)