facebook/react · error · Error

The `<head>` tag may only be rendered once.

Error message

The `<head>` tag may only be rendered once.

What it means

Thrown by pushStartHead when a second document-level <head> begins rendering. The first <head> at document position stores its chunks on the request's preamble (preamble.headChunks); a second one finds that slot occupied and throws, because the HTML document model allows exactly one head. This check only applies while insertionMode < HTML_MODE, i.e. heads rendered in the document preamble position rather than inside body content.

Source

Thrown at packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js:3740

// These are used by the client if we clear a boundary and we find these, then we
// also clear the singleton as well.
const headPreambleContributionChunk = stringToPrecomputedChunk('<!--head-->');
const bodyPreambleContributionChunk = stringToPrecomputedChunk('<!--body-->');
const htmlPreambleContributionChunk = stringToPrecomputedChunk('<!--html-->');

function pushStartHead(
  target: Array<Chunk | PrecomputedChunk>,
  props: Object,
  renderState: RenderState,
  preambleState: null | PreambleState,
  formatContext: FormatContext,
): ReactNodeList {
  if (formatContext.insertionMode < HTML_MODE) {
    // This <head> is the Document.head and should be part of the preamble
    const preamble = preambleState || renderState.preamble;

    if (preamble.headChunks) {
      throw new Error(`The ${'`<head>`'} tag may only be rendered once.`);
    }

    // Insert a marker in the body where the contribution to the head was in case we need to clear it.
    if (preambleState !== null) {
      target.push(headPreambleContributionChunk);
    }

    preamble.headChunks = [];
    return pushStartSingletonElement(
      preamble.headChunks,
      props,
      'head',
      formatContext,
    );
  } else {
    // This <head> is deep and is likely just an error. we emit it inline though.
    // Validation should warn that this tag is the the wrong spot.
    return pushStartGenericElement(target, props, 'head', formatContext);

View on GitHub (pinned to eafeac097b)

Solutions

  1. Render <head> exactly once, in the root layout, and let other components contribute via hoistable metadata (<title>, <meta>, <link> hoist automatically to it)
  2. Search the tree for all <head> occurrences and delete the duplicates
  3. If multiple modules need head content, hoist individual tags (<title>, <meta>) instead of a second <head>

Example fix

// before (root layout)
<html><head>...</head><body>{children}</body></html>
// plus a page also rendering <head>...</head>

// after: head only in the root layout
// page.jsx
<>
  <title>Page</title>
  <meta name="x" content="y" />
</>
Defensive patterns

Strategy: validation

Validate before calling

// enforce a single <head> across the app: only the root layout renders it
let headRendered = false;
function DocumentHead() {
  if (headRendered) throw new Error('Only one <head> allowed; hoist <title>/<meta> instead');
  headRendered = true;
  return <head />;
}

Prevention

When it happens

Trigger: Server-rendering a tree that contains <head> twice at the top level — e.g. a root layout rendering <html><head>...</head> while a nested layout/route also renders <head>, or two components each emitting their own <head> before the body starts.

Common situations: Framework layouts where both the shell and a page try to own <head>; adopting a head-manager library alongside an explicit <head>; refactors that moved a head-rendering component into a route rendered together with an existing one.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/090715e27cd91de7. Report an issue: GitHub.