apocalypse

dev

How to debug Next.js client-side application error

#Preface

I was working on my app the other day, and after a long development session, I decided to push everything to the main branch and call it a day. My main branch is the one connected to the production pipeline of my app, so as soon as I pushed the changes, a new production build has started. Just a few seconds after the success log message, I went to see if my app is still up and running, and that's when I got a bit nervous.

#The error

Instead of the homepage of my app, I was presented this:

Error message from VercelError message from Vercel

For a better SEO, I'm gonna paste the content here as well

Application error: a client-side exception has occurred (see the browser console for more information).

I went to see the console right away, but there was nothing of use. There was an error, sure, but the stack trace didn't point to anything I could remotely recall. The area of the error message, that the CEO of React himself pointed in a GitHub issue, as the one where things actually went south in code, was an internal Next.js Router module. I was cooked. I pushed quite a lot of code that I didn't want to revert, so I went on a hunt.

#The debugging

I see debugging as an art of asking the right questions, so let's ask a few questions that could lead us closer to the solution for this issue.

#When did you encounter this error for the first time?

In my case, it was after I pushed this giant bulk of commits to the main branch. Generally, I tend to make a code review for myself each time I'm about to make a commit, so I often notice some weird issues or inconsistencies beforehand, but this time something must've slipped through. It's good to walk through each change you make and determine if that's something that could crash your app.

If you went through the latest changes and everything looks legit, or there are too many changes, and you don't want to waste time, let's identify when this error happens.

#Is it a global error, or a route error?

In my case, this error was happening on each route. That points us to the layout.tsx file of the app, as it's the one that is being rendered on every route. It will be helpful to utilize the global-error.tsx special file, that act as an error boundary for the root layout and can prevent app from permanent crash. You will also get access to the error object that you can log in the browser for more context.

global-error.tsx
'use client' export default function GlobalError({ error, reset, }: { error: Error & { digest?: string } reset: () => void }) { // inspect the error in more details console.log(error); return ( <html> <body> <h2>Something went wrong!</h2> <button onClick={() => reset()}>Try again</button> </body> </html> ) }

If the error only happens on a specific route - start from the page.tsx file for this route and go deeper through the components tree. Any client-side error that happen for this route, will be caught by the closest error.tsx file.

It can still also be an issue that has its roots in the layout.tsx, so if you're out of ideas - try to search for an issue there as well.

#Does this error happen only in production?

If you didn't encounter this issue during development, chances are, it's something specific for your cloud provider. That will most likely be a bad news, especially if you're on a free tier, because then you'll probably be left on your own. Before you lose all hope, though, try to run a production build in your local environment and see if the bug is present there as well. Maybe you just added some process.env.NODE_ENV === 'development' check, and it's preventing your local version of the app from throwing an error.

#Did you add or update some packages?

Did you? Sometimes, when you try to use the cutting-edge, @latest versions of packages, you run into some unusual compatibility issues, that are not even documented or reported yet and that will probably be fixed in another patch/release. If neither of the previous solutions were applicable, give this one a shot and revert your package(-lock).json to the state it was before the crash.

#Maybe, just... redeploy?

Yeah, I know. Silly suggestion. Unless? Maybe it's one of those one in a million race conditions that led to your application being built with a flaw (like some .js file that went missing for no particular reason), and the issue will disappear if you just run the build once again.

#The hard way.

If none of the above helped, try to revert the changes and then add them slowly one by one, observing which one makes the error show up. Life is hard, and sometimes it's the only way to determine where the issue comes from.

#What was wrong in my code

In my case, it was actually quite easy to spot.

  • The crash was happening on each route ➡️ probable cause was somewhere in the layout.tsx
  • The crash was client-only ➡️ my layout has the use client declaration on top
  • The crash happened only in production ➡️ could have something to do with checking the process.env.NODE_ENV

And there we go (I hope the image quality won't stand in a way too much):

providers.tsx file that is imported in the layout.tsxproviders.tsx file that is imported in the layout.tsx

As I was removing console.logs from the production version of the app, I went a bit overboard, and I missed the fact that within the if block, there was actually some quite important code, initializing React Query client, that I completely cut out from the production build.

Sometimes a rookie mistake like this can take down your entire app for good, so it's good to have a mental framework for situations like this - to be able to ask the right questions that can speed up the debugging process. While I consider Next.js to be quite experimental and unstable, especially on the @latest releases, the reason for a buggy behavior or straight up crashes may very likely lay in your implementation or misunderstanding of a certain feature, don't forget about it ;).

Related tags:

Application
error
client-side
exception
occurred
browser
console
vercel
next
nextjs
production
global-error