vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.83k stars 26.96k forks source link

Misleading "next-head-count is missing" error for invalid head tags #20924

Open aengl opened 3 years ago

aengl commented 3 years ago

What version of Next.js are you using?

10.0.5

What version of Node.js are you using?

12.20.1

What browser are you using?

Chrome

What operating system are you using?

macOS

How are you deploying your application?

Vercel

Describe the Bug

When using an unsupported/invalid tag in next/head, the console shows an unhelpful next-head-count is missing error and the content of next/head ends up in the body tag.

Example:

<Head>
  {/* The following line causes an error */}
  <html lang="en" />
  <title>Demo Page</title>
</Head>

Expected Behavior

Next.js should warn about the offending tag and gracefully ignore it.

To Reproduce

https://github.com/aengl/next-head-count-missing

Check out the project, run it via yarn dev and check the console output on the index page to see the error. Check the inspector to verify that the title tag was written into the HTML body.

Remove line 6 in components/SEO.tsx and the error will disappear:

<html lang="en" />

More extensive discussion of this error can be found here: https://github.com/vercel/next.js/issues/19361

JorgeSivil commented 3 years ago

Same happened to us in another component

const MetaData = ({ pageData }) => {
  /**
   * For some NextJS reason, if you move this to the return, errors occur in console. "next-head-count is missing"
   * @return {JSX.Element}
   */
  const XxxId = () => {
    return <meta name="xxxid" property="xxxid" content={pageData.xxx.id} />;
  };

  return (
    <>
      <NoIndexMetaData pageData={pageData} />
      <link
        rel="canonical"
        href={`${
          pageData.canonicalLink.indexOf('//') === 0 ? `https:${pageData.canonicalLink}` : pageData.canonicalLink
        }${pageData.page > 1 ? `?page=${pageData.page}` : ''}`}
      />
      <link rel="publisher" href="https://plus.google.com/xxxxxx" />
      <XxxId />
      <TwitterMetaData pageData={pageData} />
      <OpenGraphMetaData pageData={pageData} />
    </>
  );
};

This is used in the component from nextjs

ghrqq commented 3 years ago

Next.js's head count error may be caused by either literally wrong head count or using a tag within the Head which is not allowed. (For the other discussions you have m entioned nested elements also causes it)

title, meta or any other elements (e.g. script) need to be contained as direct children of the Head element, or wrapped into maximum one level of or arrays—otherwise the tags won't be correctly picked up on client-side navigations. more here

HTML tag is not allowed within the Head component because during the render, Next.js places the Head component directly within the html tag where it belongs. 2021-04-11 07 32 54 pm

As a result when you type a html element within the Head component it causes error and because of this error, Head component does not deliver the data while Next.js expects a Head data, it does not receive and you see a head count error.

You may try to create a custom document and place the lang attribute in there.

Here is the example of what happens to the rendered head element when you use an illegal element.

2021-04-11 07 38 01 pm 2021-04-11 07 38 58 pm

jonrh commented 3 years ago

Had this happen and it took quite a while to figure out. A clearer warning as proposed would have been great. I was migrating a project from Gatsby to Next.js. In that migration I switched from react-helmet to next/head. To improve accessibility <html lang="is"> was specified. In react-helmet it is valid but it is not supported in next/head. As a result I got the next-head-count error and all <head> tags appeared in <body> instead.

migueloller commented 3 years ago

It happened to me as well but in our case it was due to a user-provided snippet that included a <div> element. The browser seems to move everything after the <div> to the body resulting in Next.js not being able to find <meta name="next-head-count"> when calling querySelector("meta[name=next-head-count]").

Here's the lines of code where it happens: https://github.com/vercel/next.js/blob/6ad91722954049ffb5e23435f2b3fb4ba94d7cc2/packages/next/client/head-manager.ts#L45-L47

It's worth noting that it's not Next.js that places the invalid HTML in the body, but it's instead the browser, Chrome in my case. The response from the server indeed has the <div> in the head. So the problem here is Next.js just not being able to find the <meta name="next-head-count"> tag.

Since the browser seems to move everything that's after the invalid tag a potential solution for this would be to move the <meta name="next-head-count"> tag to the beginning of next/head's output instead of at the end.

timneutkens commented 2 years ago

This can now be an ESLint rule I believe

itsjavi commented 1 year ago

This is also triggered when you accidentally nested Head elements, one inside another. It's a stupid mistake from dev side, but I spent quite of time trying to figure out what was going on, because the error message was not helpful enough.

sandeepkumar03 commented 1 month ago

Related issue https://github.com/vercel/next.js/issues/50944, I think an uncaught error is happening in production breaking the page, probably page should be allowed to render like hydration errors. Not sure the reason of hard dependency of need of next-head-count at framework level that framework throws runtime error breaking the complete page. Unfortunately control also doesn't goes to _error file to handle it gracefully.