Uncaught Error: invariant expected app router to be mounted
Asked Answered
A

11

40

I've got an error while do migration to next 13 on my old project written in next 12.

Console Error Log

I can't find fault in my code for that errors. And I googled it but i can't find any solution for this. It don't explains any errors for my code. How can I solve it?

I couldn't try anything because it do not explains any error for my code. Please let me know what is the origin for that error. Thank you.

++++++++++ navigation.js

function useRouter() {
    const router = (0, _react).useContext(_appRouterContext.AppRouterContext);
    if (router === null) {
        throw new Error('invariant expected app router to be mounted');
    }
    return router;
}

i think "next/navigation" contains this file (navigation.js)

this error threw when router is null, but i still can't know why router is null.

+++++++++++ layout.jsx

"use client";

import { motion, AnimatePresence } from "framer-motion";
import "animate.css";
import { useRouter } from "next/navigation";
import LoadingSpinner from "../components/layout/media/LoadingSpinner";

import Users from "../class/Users.class";

import { useEffect } from "react";
import create from "zustand";

import Head from "next/head";
import Image from "next/image";

import NavBar from "../components/layout/NavBar";
import SubTransition from "../components/transition/SubTransition";
import LoginModal from "../components/layout/LoginModal";

import "../styles/betconstruct_icons.css";
import "../styles/global.css";

const useStore = create(() => ({
  isShowLoginModal: false,
  isLoading: true,
}));

//default layout
function MainLayout({ children }) {
  

  useEffect(() => {
    Users.checkToken().then((res) => {
      if (res) {
        console.log("token is valid");
      } else {
        console.log("token is invalid");
      }
      LoadingDone();
    });
    //router.events.on("routeChangeStart", (url) => {
    //  LoadingNow();
    //});
    //router.events.on("routeChangeComplete", () => LoadingDone());
    //router.events.on("routeChangeError", () => LoadingDone());

    if (router.pathname === "/") {
      document.querySelector("body").classList.add("layout-bc");
      document.querySelector("body").classList.add("theme-default");
      document.querySelector("body").classList.add("smart-panel-is-visible");
      document.querySelector("body").classList.add("betslip-Hidden");
      document.querySelector("body").classList.add("is-home-page");
    }

    if (router.pathname !== "/") {
      document.querySelector("body").classList.add("layout-bc");
      document.querySelector("body").classList.add("theme-default");
      document.querySelector("body").classList.add("smart-panel-is-visible");
      document.querySelector("body").classList.add("betslip-Hidden");
      document.querySelector("body").classList.add("is-home-page");
    }
  }, []);

  const animate = {
    initial: {
      opacity: 0,
      transition: `transform 0.24s ease`,
    },
    animate: {
      opacity: 1,
      transition: `transform 0.24s ease`,
    },
    exit: {
      opacity: 0,
      transition: `transform 0.24s ease`,
    },
  };

  const animateFlyIn = {
    initial: {
      opacity: 0,
      x: 100,
      transition: `transform 0.24s ease`,
    },
    animate: {
      opacity: 1,
      x: 0,
      transition: `transform 0.24s ease`,
    },
    exit: {
      opacity: 0,
      x: 100,
      transition: `transform 0.24s ease`,
    },
  };

  const { isShowLoginModal, isLoading } = useStore();
  const openLoginModal = () => {
    useStore.setState({ isShowLoginModal: true });
  };
  const hideLoginModal = () => {
    useStore.setState({ isShowLoginModal: false });
  };
  const LoadingNow = () => {
    useStore.setState({ isLoading: true });
  };

  const LoadingDone = () => {
    useStore.setState({ isLoading: false });
  };

  const router = useRouter();

  return (
    <>
      <AnimatePresence exitBeforeEnter mode={"wait"}>
        {isLoading ? (
          <motion.div
            key={router.route}
            initial={animate.initial}
            animate={animate.animate}
            exit={animate.exit}
          >
            <LoadingSpinner router={router} />
          </motion.div>
        ) : null}

        {isShowLoginModal && (
          <LoginModal
            openLoginModal={openLoginModal}
            isShowLoginModal={isShowLoginModal}
            hideLoginModal={hideLoginModal}
            LoadingNow={LoadingNow}
            LoadingDone={LoadingDone}
          />
        )}
      </AnimatePresence>
      <NavBar
        isLoading={isLoading}
        isShowLoginModal={isShowLoginModal}
        openLoginModal={openLoginModal}
        hideLoginModal={hideLoginModal}
        LoadingNow={LoadingNow}
        LoadingDone={LoadingDone}
        router={router}
      />
      <SubTransition>
        <div className="layout-content-holder-bc">{children}</div>
      </SubTransition>
    </>
  );
}

export default MainLayout;

+++ This error not occurs for /pages directory. only occurs in using /app directory

Aeolian answered 21/11, 2022 at 8:3 Comment(5)
@xlab Please edit your question and put the code there. That way it becomes more readable for all of us.Ruhnke
@xlab please add the code where you are using the useRouter() Hook. NextJS Framework code isn't helpful. We need to see the code you wrote in order to see what's wrong.Heikeheil
@ShivangamSoni updated just now.Aeolian
In addition to your code, can you please tell us whether you are using the app directory or the pages directory pattern?Ruhnke
@Ruhnke This error not occurs for /pages directory. only occurs in using /app directoryAeolian
N
146

Happened to me when layout.tsx didn't have <body> and <html> tag.

Edit:

Here is the exact section from documentation

The root layout must define <html> and <body> tags since Next.js does not automatically create them.

Nadya answered 28/11, 2022 at 13:11 Comment(6)
Same here, html was missing tooAllies
Damn, nice. This should be opened as an issue on Next.js' github for a better error message.Rabblement
This was my issue as well. Agreed, better error message would be helpfulClair
I had similar issue.. I have wrapped html tag inside Provider. Ideally Provider should be wrapped inside html tag which solved my issueFilippa
This is the answer everyone is looking for. In production this will result in Minified React error #418;Micron
Just going to add that this affected me when running Sanity Studio. Hope this helps others find the solution.Grubbs
A
10

While transferring the files to the new app the same error popped up which led me to believe it was something in the code I copied over. The issue was in my layout.tsx file that was causing hydration / mounting issues because of a dom mismatch.

Old layout causing bug

export default function RootLayout({ children}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
    <div className={styles.container}>
      <header className={styles.header}>
          <>
            <Image
              priority
              src="/images/profile.jpg"
              className={utilStyles.borderCircle}
              height={144}
              width={144}
              alt=""
            />
            <h1 className={utilStyles.heading2Xl}>{name}</h1>
          </>
      </header>
      <main>{children}</main>
    </div>
    </html>
  );

Fixed code in layout.tsx

export default function RootLayout({ children}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
    <head className={styles.header}>
    </head>
    <body>{children}</body>
    </html>
  );
}

Even better: reference layout from beta docs

export default function RootLayout({ children }) {
  return (
    <html lang="en">
    {
    }
    <head />
    <body>{children}</body>
    </html>
  );
}

**Errors for reference if anyone else is encountering this problem.

Uncaught Error: invariant expected app router to be mounted

react-dom.development.js:21494 The above error occurred in the component:
at HotReload (webpack-internal:///./node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:19:11)**
Aeolian answered 21/11, 2022 at 14:45 Comment(0)
L
7

Don't put any Wrapper Element outside body tag like this

   <AUthProvider>
    <body>
          {children}
     </body>
   </AuthProvider>

but make sure that body tag always includes all components

    <body>
       <AUthProvider>
          {children}
      <AUthProvider>
    </body>

hopefully this helps

Lockage answered 1/7, 2023 at 23:11 Comment(2)
this did not work for me: <html lang="en"><body className={inter.className}><div>{children}</div></body></html>, note: I wrapped the children in a div. Any explanation would be a plus for this answerAstyanax
This helped me. Make sure your tag order is correct, people. Thanks!Jaehne
F
6

I solved this problem in version 13.4.19

When you want to use app directory, you use different layers, so you must use <html></html> and <body><body /> tags in each layer.

for example

app/(home)/layout.tsx

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>{children}</body>
    </html>
  )
}

app/(auth)/layout.tsx

export default function AuthLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>{children}</body>
    </html>
  )
}
Filtration answered 3/9, 2023 at 8:41 Comment(1)
Really crazy but worked, and also one more discovery, you cannot have this: <html lang="en"><body className={inter.className}><div>{children}</div></body></html>, note: I wrapped the children in a div. Any explanation would be a plus for this answerAstyanax
A
3

The top-most layout is called the Root Layout. This required layout is shared across all pages in an application. Root layouts must contain html and body tags.

export default function RootLayout({ children }: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Sources:

Arose answered 5/1, 2023 at 16:29 Comment(2)
That answer comes after the other ones but is much better. It is easy to miss that Root Layout (Required) must have html and body tags.Teflon
Improved mine to include actual wording from the documentation.Nadya
T
3

If you have this error with storybook (@storybook/nextjs) then you need to have a parameter in your preview.tsx

const preview: Preview = {
  parameters: {
    nextjs: { appDirectory: true },
  },
};
Tomfoolery answered 23/1 at 16:6 Comment(0)
E
0

I had the same problem and it was because I was wrapping my <body/> component on the layout file with another component. Apparently you shouldn't do that and instead wrap your {children} component with whatever you are wrapping your body component, just like this:

  <html lang="en">
      <body>
        <SideBar>{children}</SideBar>
      </body>
  </html>
Eton answered 11/4, 2023 at 15:33 Comment(1)
Yeah, it's not only body. I was missing the entire html base structure.Sontag
C
0

If you have other components inside the _app.js that you had copied over to layout.js (e.g. theme provider, redux, redux persist), it should be inside the <body> tag. Basically, it worked for me when the <body> tag was the first child of the <html> tag.

Cerussite answered 5/6, 2023 at 1:55 Comment(0)
M
0

FWIW, I had a basic loading.tsx placed at the root app level. Once I moved it into the page subfolder under app folder it started working again.

Matney answered 30/6, 2023 at 3:29 Comment(0)
J
0

I got this same error when I accidentally imported next/navigation instead of next/router. Easily done it seems - the useRouter hook exists on both and has a similar interface.

Janerich answered 27/2 at 20:41 Comment(0)
L
0

I had the same error, because I was missing a default.js file at the root of the slot.

See the docs

Lyris answered 8/5 at 18:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.