facebook/docusaurus · error · Error
"${val}" is not a valid HTML tag object.
Error message
"${val}" is not a valid HTML tag object. What it means
Thrown by the internal `assertIsHtmlTagObject` guard when a value used as an HTML tag (in `headTags`/`scripts`/`stylesheets`) is not a non-null object. Docusaurus expects each tag entry to be either a string or an `HtmlTagObject`; a primitive/null/undefined fails this first check. The TODO in source notes this should ideally run at config validation time.
Source
Thrown at packages/docusaurus/src/server/htmlTags.ts:23
* LICENSE file in the root directory of this source tree.
*/
import _ from 'lodash';
import htmlTags from 'html-tags';
import voidHtmlTags from 'html-tags/void';
import escapeHTML from 'escape-html';
import type {
Props,
HtmlTagObject,
HtmlTags,
LoadedPlugin,
RouterType,
} from '@docusaurus/types';
// TODO this should be done at config validation time, not here
function assertIsHtmlTagObject(val: unknown): asserts val is HtmlTagObject {
if (typeof val !== 'object' || !val) {
throw new Error(`"${val}" is not a valid HTML tag object.`);
}
const htmlTag = val as HtmlTagObject;
if (typeof htmlTag.tagName !== 'string') {
throw new Error(
`${JSON.stringify(
val,
)} is not a valid HTML tag object. "tagName" must be defined as a string.`,
);
}
if (
!htmlTag.customElement &&
!(htmlTags as string[]).includes(htmlTag.tagName)
) {
throw new Error(
`Error loading ${JSON.stringify(val)}, "${
htmlTag.tagName
}" is not a valid HTML tag. Either use a valid "tagName" or set "customElement: true".`,
);View on GitHub (pinned to 3f483e80e3)
Solutions
- Ensure every entry in your tags arrays is either a string or a full `HtmlTagObject` (`{tagName, attributes, innerHTML}`).
- Filter out falsy values before returning: `tags.filter(Boolean)`.
- Audit plugin `injectHtmlTags`/`injectStyles`/`injectScripts` return values for conditional `undefined`.
Example fix
// before
headTags: [shouldAddMeta && {tagName: 'meta', attributes: {...}}],
// after
headTags: [shouldAddMeta && {tagName: 'meta', attributes: {...}}].filter(Boolean), Defensive patterns
Strategy: validation
Validate before calling
function sanitizeTags(tags: unknown[]): HtmlTagObject[] {
return tags.filter((t): t is HtmlTagObject =>
typeof t === 'string' || (typeof t === 'object' && t !== null));
} Type guard
function isHtmlTagObject(v: unknown): v is {tagName: string; attributes?: Record<string,string>; innerHTML?: string} {
return typeof v === 'object' && v !== null;
} Prevention
- Always `.filter(Boolean)` before returning tag arrays from plugins.
- Type plugin `injectHtmlTags` returns as `HtmlTags`.
- Avoid conditional `&&` shorthand inside arrays without filtering.
When it happens
Trigger: Passing `null`, `undefined`, a number, or a boolean into one of the `headTags`, `scripts`, or `stylesheets` arrays in docusaurus.config.js or a plugin's injected tags. The `typeof val !== 'object' || !val` branch at htmlTags.ts:23 catches every non-object.
Common situations: Returning `undefined` from a plugin's `injectHtmlTags` hook due to a conditional bug; spreading a possibly-undefined array of tags; a typo producing `0` or `false` instead of a tag object.
Related errors
- ${JSON.stringify(val)} is not a valid HTML tag object. "tagN
- Error loading ${JSON.stringify(val)}, "${htmlTag.tagName}" i
- Unexpected "reportingSeverity" value: ${reportingSeverity}.
- ${JSON.stringify(redirect)} => Validation error: ${error.mes
- Invalid sidebars file. The document with id "${docId}" was u
AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12).
Data as JSON: /api/errors/4f52f548f47ab3f3.
Report an issue: GitHub.