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

  1. Ensure every entry in your tags arrays is either a string or a full `HtmlTagObject` (`{tagName, attributes, innerHTML}`).
  2. Filter out falsy values before returning: `tags.filter(Boolean)`.
  3. 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

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


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/4f52f548f47ab3f3. Report an issue: GitHub.