Share on Twitter
Share on Facebook
Share on HackerNews
Share on LinkedIn

Common Errors in Next.js and How to Resolve Them

Bugs are one of the most troubling aspects of software development; they appear out of nowhere and cause everything to stop working. Most of the time, they can be resolved quickly; however, others can be gruesome and take hours/days to fix.

Next.js is one of the most popular web development frameworks in the current world, and as a programming tool, it didn’t escape the bug dilemma either.

To save you the back and forth, this article will explore some of the most common Next.js errors reported by developers on different platforms; we’ll cover why these bugs happen, as well as how to resolve them. Without further ado, let’s get right into it.

Document/Window Object Error

One of the most common errors in Next.js is the document/window is not defined error. Why does it happen? This error typically appears when you or an installed package try to access the browser’s window objects directly in a page component, and Next.js will throw this error because the window object is not yet available while a component is still mounting.

Say we have a sample index.js page in our Next.js application and try to access the browser localStorage like below; we’ll get the window is not defined error.

const Index = () => {
  window.localStorage.foo = "bar";

  return (
    <>
      <div>
        <h1>Hello world!</h1>
      </div>
    </>
  );
};

export default Index;

How to resolve

There are different approaches to resolving this error, one straightforward option is to simply employ react’s useEffect() hook to execute the code block that requires the browser’s window object, so that the code is only executed when the page component had been mounted.

import { useEffect } from "react";

const Index = () => {
  useEffect(() => {
    window.localStorage.foo = "bar";
  }, []);

  return (
    <>
      <div>
        <h1>Welcome to my Blog!</h1>
      </div>
    </>
  );
};

export default Index;

Another option is to convert the part of our code that requires the browser’s window to a standalone component and import it to our page component using Next.js dynamic import feature. Next’s dynamic import is a feature used to lazy-loading or dynamically load components on demand. However, it includes an additional ssr option that allows you to enable or disable server rendering when using it.

We can simply set the ssr value to false and will be able to load components or external packages that rely on the browser’s window or document.

// components/SampleComponent.js

const SampleComponent = () => {
  window.localStorage.foo = "bar";

  return (
    <>
      <div>
        <h1>Welcome to my Blog!</h1>
      </div>
    </>
  );
};

export default SampleComponent;

And dynamically load it in a page.

// pages/index.js
import dynamic from "next/dynamic";

const DynamicComponent = dynamic(
  () => import("../components/SampleComponent"),
  {
    ssr: false,
  }
);

const Index = () => {
  return (
    <>
      <div>
        <h1>Hello world!</h1>
        <DynamicComponent />
      </div>
    </>
  );
};

export default Index;

Middleware Error

Middleware enables the execution of code prior to the completion of a request, and based on the incoming request, it modifies the response sent to the user by rewriting, redirecting, or even adding headers.

One error you could encounter when working with middleware in Next.js is

TypeError: Invalid URL

This error usually happens when you’re using Next.js with a custom server, and you did not explicitly specify the server host URL in your configuration; additionally, if you are using a monorepo build system like Nx, you’d also likely experience this error as tools like this one creates a custom server for you behind the scene.

How to resolve

You can quickly fix this error by specifying the hostname in your server configuration file. If you are using nx, you can do this by modifying the serve options in your project configuration file (project.js). I.e., you modify this file to look like this.

 "serve": {
    "executor": "@nrwl/next:server",
    "defaultConfiguration": "development",
    "options": {
      "buildTarget": "test-nx:build",
      "dev": true,
      "port": 4200,
      "hostname": "localhost"
    },
    . . .
  }

Middleware not triggered

In rare cases where your middleware code seems to not be triggered at all, this might have happened due to the incorrect placement of your middleware file.

How to resolve

In older versions of Next.js, you create your middleware file as _middleware.js in the /pages directory. However, the latest versions of Next.js require that you save this file as middleware.js on the root folder, i.e. the same level as the /pages directory.

With this new change, your file structure should look like this.

.
├── . . .
├── pages
│   └── index.js
├── public
├── middleware.js
└── . . .

API/Slug Error

Next.js is shipped with the getStaticPaths and getServerSideProps API for data fetching; however, they occasionally throw errors when used incorrectly.

One of these errors, specifically with the getStaticProps API, is:

error - Error: getStaticPaths is required for dynamic SSG pages and is missing for '/pageName/[slug]'

This error occurs when a dynamic page is being rendered on the server-side using the Static Site Generation (SSG) feature in next.js, but the getStaticPaths() function is not defined in the page’s component.

The getStaticPaths function is a required part of the Next.js API for building server-side rendered (SSR) or statically generated (SSG) pages that use dynamic routes.

How to resolve

To fix this error, you will need to add a getStaticPaths() function to the page component for /pageName/[slug].

For example, if the page at /pageName/[slug] is meant to display information about a blog post, the getStaticPaths function could fetch a list of all the available blog post slugs from a database and return them as the possible values for the [slug] parameter.

export async function getStaticPaths() {
  // fetch list of available slugs from a database
  const res = await fetch('http://localhost/path/to/blogs')
  const posts = await res.json()
  const slugs = posts.map(post => post.slug)

  // return the possible values for the [slug] parameter
  return {
    paths: slugs.map((slug) => ({ params: { slug } })),
    fallback: false
  }
}

It is also worth mentioning that all the Next.js data fetching APIs can only be used inside page components, and will not work outside regular components.

Module Error

Another common error in Next.js is: Module not found: Can’t resolve ‘moduleName’, e.g.

Module not found: Can't resolve 'fs'

This error usually occurs when you’re importing a module that is not accessible by Next.js. Like with the case of the fs module, it is simply because the module is not available on the client side, and you or a third-party package had tried to access it.

How to resolve

You can resolve this error by making sure to keep all Node.js/server-related code inside of Next.js data fetching APIs — getServerSideProps, getStaticPaths, or getStaticProps.

export function Index({ fileInfo }) {
  return (
    <div>
      {/* page content */}
    </div>
  );
}

export default Index;

export async function getServerSideProps(context) {
  const fs = require('fs');
  let fileInfo = fs.readFileSync('path/to/sample.txt');

  return {
    props: {
      fileInfo,
    },
  };
}

In cases where the error had occurred because of a package you imported and not because you’re explicitly trying to access a Node.js module, you can modify your Next.js configuration file (next.config.js) to include an entry for webpack like this.

const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,

  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback = {
        fs: false,
      };
    }

    return config;
  },
};

module.exports = nextConfig;

In this code, the isServer property of the options object is checked to determine if the current build is for the server-side or the client-side. If the build is not for the server-side (i.e. if isServer is false), then the fs module is added to the fallback list in the resolve section of the webpack configuration.

This means that when webpack encounters an import for the fs module, it will not attempt to resolve the import, and the fs module will not be bundled with the application. This allows the fs module to be loaded at runtime on the server-side, but not on the client-side.

If you’re not using Node.js modules and still get the “module not found” error, ensure the module has been installed and imported properly. There may be a casing error, so double-check that.

Cors Error (Next API Routes)

Next.js allows users to create REST API endpoints by placing files with the desired endpoint names inside the /pages/api directory. These endpoints are then mapped to the /api/* URL and can be accessed from within the application by making asynchronous requests.

However, once your application has been deployed and you try to access the API endpoint from a different origin, you get the cors error like the one below.

Access to fetch at 'http://example.com/api/hello' from origin 'http://localhost:3001' has been blocked by CORS policy ...

How to resolve

We can fix this error by leveraging the popular cors package to enable cross-origin sharing before our API route sends its response. To do this, first, we have to install the cors package.

npm install cors
# OR
yarn add cors

After that, we can import this package to run custom middleware before the API route sends its response, enabling the preferred method for the specific endpoint; for example, we can enable the POST, GET, and HEAD methods for this endpoint.

// pages/api/hello.js

import Cors from "cors";

const cors = Cors({
  methods: ["POST", "GET", "HEAD"],
});

function runMiddleware(req, res, fn) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result) => {
      if (result instanceof Error) {
        return reject(result);
      }
      return resolve(result);
    });
  });
}

export default async function handler(req, res) {
  await runMiddleware(req, res, cors);

  // Other API logic
  res.json({ foo: "bar" });
}

You should stop experiencing cors errors once you have your API designed like this.

Monitoring Error with Sentry

Resolving errors during development writing tests is a crucial step in ensuring the quality and functionality of an application. However, it’s not enough to simply fix errors as they arise during these stages. It’s also essential to monitor the application’s state and performance in production, where it will be used by actual users. This is because errors and performance issues not detected during development and testing may still occur in the production environment.

Sentry can help identify these issues by tracking your application’s state and performance in real-time. You can configure your application to alert the development team when errors occur, allowing them to quickly address the issue and prevent it from impacting the user experience.

Additionally, Sentry provides valuable insights regarding your application’s performance, such as response times and resource usage, which can help you optimize your application and improve its overall reliability.

Recap

Next.js is a popular and powerful framework for building web applications; however, like any technology, it is not immune to errors and issues. This article has covered some common errors in Next.js, what causes these errors, as well as how to resolve them.

We also emphasized the importance of using a monitoring tool to continually track the state of your application. To get started with monitoring your Next.js application check out this helpful guide.

Your code is broken. Let's Fix it.
Get Started

More from the Sentry blog

ChangelogCodecovDashboardsDiscoverDogfooding ChroniclesEcosystemError MonitoringEventsGuest PostsMobileOpen SourcePerformance MonitoringRelease HealthResourceSDK UpdatesSentry
© 2024 • Sentry is a registered Trademark
of Functional Software, Inc.