Back to Blog Home

Using distributed tracing to debug timeout errors in Next.js

Matthew C. image

Matthew C. -

Using distributed tracing to debug timeout errors in Next.js

Next.js lets you write the UI, the API, and everything in between, so when a request stalls it can feel like you’re chasing a bug through a hall of mirrors. With distributed tracing in your workflow, those mirrors flatten into a single timeline that lists every route hop, database call, and third-party handshake in order. Now you can follow the delay from click to response without digging through log files or swapping tabs.

Tracing captures the sequence of requests and operations in your app, while distributed tracing extends this capability across services or APIs, even if they use different languages and platforms. This end-to-end visibility helps you find performance issues and the root cause of errors by following the flow of requests and operations from the frontend to the backend.

In this post we’ll break down a stubborn timeout in a Vercel-deployed Next.js notes app that leans on Server Actions for moving data. With Sentry’s Trace View, each step shows up like breadcrumb arrows you can actually follow. This allows you to quickly and effectively debug the issue, getting you right back into building instead.

Debugging a Statement Timeout Error in a Next.js App With Server Actions

We created an example Next.js note-taking app using Vercel’s Next.js Supabase starter. The app has cookie-based authentication and uses Server Actions (async functions executed on the server) to read, edit, and create notes. Server Actions can be called in server or client components to handle form submissions and data mutations without needing to create an API.

The Next.js example note-taking app includes a statement timeout error that we’ll debug using Sentry’s distributed tracing.

Clone the Next.js Note-Taking App

Start by cloning the GitHub repository for the starter Next.js app, which uses Supabase to store user data. Follow the steps in the README to set up the app, add example notes to Supabase, and deploy it to Vercel.

Set Up and Configure Sentry in a Next.js App

If you already have a Sentry account, then you're good to go. If not, head over to the signup page and create an account to get started with the next steps.

Once you’ve signed up, follow the onboarding steps to create a new project for a Next.js app. Alternatively if you’re already a bit familiar with Sentry, create a new project and select Next.js as the platform.

Add the Sentry Next.js SDK to the note-taking app by running the Sentry wizard in the root of the project (remember to replace the --org and --project options with your own variables):

Click to Copy
npx @sentry/wizard@latest -i nextjs --saas --org <your-org-name> --project <your-project-name>

This command installs the @sentry/nextjs npm package and automatically configures Sentry for your app.

You’ll be asked the following questions in the CLI. Answer “yes” to each.

Click to Copy
◇  Do you want to route Sentry requests in the browser through your Next.js server to avoid ad blockers?
│  Yes
◇  Do you want to enable Tracing to track the performance of your application?
│  Yes
◇  Do you want to enable Session Replay to get a video-like reproduction of errors during a user session?
│  Yes
◇  Do you want to create an example page ("/sentry-example-page") to test your Sentry setup?
│  Yes
◇  Are you using a CI/CD tool to build and deploy your application?
│  Yes

Add the code snippet provided by the setup wizard to the next.config.ts file. Remember to replace yourNextConfig with nextConfig as defined in the file.

Replace the contents of the app/global-error.tsx file with the code snippet provided by the setup wizard. Import the default Next.js error page component:

Click to Copy
import NextError from "next/error";

Replace the placeholder comment with the default Next.js error page component:

Click to Copy
- {/* Your Error component here... */}
+ <NextError statusCode={0} />

To validate the Sentry setup, first run your development server:

Click to Copy
npm run dev

Then visit the /sentry-example-page route in your browser. For most Next.js applications, this will be at localhost.

Sentry example page route - with error generating button

Click the Throw Sample Error button and then open your project in the Sentry dashboard. You’ll see the two example errors as Sentry issues:

Example issues in Sentry dashboard

You can click on an issue to get more details about it:

Example issue details

Note that Sentry focuses on reporting unhandled errors, like the ones above. It doesn’t automatically detect errors caught in a try...catch block or similar error-handling mechanism, and it won’t mark them as handled unless you report them explicitly.

Sentry provides a captureException() method to capture handled errors. It takes an Error object as an argument:

Click to Copy
import * as Sentry from "@sentry/browser";

try {
  aFunctionThatMightFail();
} catch (err) {
  Sentry.captureException(err);
}

You can manually capture a message using the captureMessage() method:

Click to Copy
Sentry.captureMessage("Something went wrong");

Upload Source Maps to Sentry

Source maps enable readable stack traces in your errors, allowing you to see where an error originates in the original, unminified code.

The @sentry/nextjs package automatically generates and uploads source maps. If you’re deploying with Vercel, use the Vercel integration to handle source map uploads during deployment.

To install the Sentry integration on Vercel, click the Connect Account button:

Sentry Vercel integration

In the popup, select the note-taking app project and click Connect Account.

Now connect your Sentry project to the Vercel project:

Connect Sentry project to Vercel project

You’ll notice additional environment variables in the Vercel project:

Environment variables added to Vercel project

Instrument Next.js Server Actions

In the Next.js app, wrap the getNotes function with the Sentry withServerActionInstrumentation method in the actions.ts file:

Click to Copy
export async function getNotes() {
  "use server";
  try {
    return await Sentry.withServerActionInstrumentation(
      "getNotesServerAction",
      {
        recordResponse: true,
      },
      async () => {
        // Get the client
        const supabase = await createClient();

        // Get the current user
        const { data: userData } = await supabase.auth.getUser();
        if (!userData.user) {
          throw new Error("User not authenticated");
        }

        const { data: notes, error } = await supabase.rpc(
          'slow_get_notes',
          { p_user_id: userData.user.id }
        );

        // If there's a database error, throw it
        if (error) {
          console.error('Error fetching notes:', error);
          Sentry.captureException(error);
          throw new Error("Failed to retrieve notes");
        }

        // Return the notes
        return notes;
      },
    );
  } catch (error) {
    // Capture the error in Sentry with full details
    console.error('Error in getNotes:', error);
    Sentry.captureException(error);

    // Create a custom error with a generic message
    const clientError = new Error("Something went wrong while loading your notes. Please try again later.");

    // Rethrow the error with generic message for the client
    throw clientError;
  }
}

Import Sentry at the top of the file along with the other imports:

Click to Copy
import * as Sentry from "@sentry/nextjs";

The modified getNotes method enables Sentry to name and identify Server Actions, capture errors, and record performance.

Sentry doesn’t currently monitor Server Actions automatically. Automatic monitoring will be added once the Next.js Turbopack bundler is stable.

Commit these changes to your remote GitHub repository. Vercel will automatically deploy your application.

API Call Timeout Troubleshooting Using Distributed Tracing

Open your deployed application and log in. You’ll see that the notes fail to load:

Notes loading error

You’ll see a connection error or a message saying there was a problem rendering the server component.

Let’s investigate the “Failed to retrieve notes” error using Sentry. Open the issue in your Sentry dashboard to see details about the error:

Failed notes loading Sentry issue

The error name doesn’t tell us much. We can see that this error occurred across two environments: a Node environment and a Linux server. The Stack Trace shows the line of code where the error occurred:

Failed notes loading issue stack trace

The error was captured as an event using Sentry’s captureException method.

Click the View Full Trace button in the Trace Preview section:

Notes loading error trace view

Tracing captures the timing and flow of requests and operations in an app. A trace is made up of transactions, which are events your application sends to Sentry. Each transaction contains spans, which are timed operations within the application flow. All transactions and spans in a trace share the same Trace ID.

The Trace View shows that the slowest transaction occurred while loading the notes page, when fetching notes using the getNotesServerAction Server Action. The POST request to Supabase was canceled due to a statement timeout.

The transaction has one span: a POST request that took 8.29 seconds:

Slowest transaction - API POST request to Supabase

With distributed tracing, Sentry allows you to trace client-side and server-side operations.

Why Did the API Request Time Out and How Do I Fix It?

In the example note-taking app, notes are fetched using the slow_get_notes Postgres function, which has a two-minute delay.

Server Actions run as Vercel functions. On the Hobby plan, these functions have a maximum execution time of 60 seconds, with a default timeout of 10 seconds.

As the function took longer than the permitted execution time, the request timed out. The same error can be caused by network connectivity issues.

Common ways to fix Server Action timeout errors include:

  • Increase the default maximum execution duration if a function is computationally expensive and is expected to take a long time. On Vercel, you can also enable fluid compute to increase the maximum execution limit for serverless functions.

  • Confirm that the function returns an HTTP response. Otherwise, Vercel will wait until the maximum duration has elapsed and then time out.

  • Ensure the function is not being called in an infinite loop – check the logic in any loops or recursive calls.

  • Check that any external API integrations are working and returning responses.

If your database queries are slow, query optimization can help. Start by indexing columns that are read often, such as those used for filtering, sorting, or joining tables. Read more about query optimization in the Supabase docs.

To take your Supabase debugging to the next level, use the Supabase + Sentry Integration to trace slow database queries and catch database errors.

Distributed Tracing Brings Clarity

Distributed tracing makes it easier to debug errors and performance issues in a Next.js app by tracking events and operations across the stack. It’s especially helpful for finding the source of timeout errors with vague error messages.

At Sentry, we used distributed tracing to quickly debug an intermittent Slack integration error affecting one of our customers. Read more about it in our blog post, Debugging a Slack Integration with Sentry’s Trace View.

To learn more about distributed tracing in Next.js, take a look at the following Sentry resources:

Share

Share on Twitter
Share on Bluesky
Share on HackerNews
Share on LinkedIn

Published

Sentry Sign Up CTA

Code breaks, fix it faster

Sign up for Sentry and monitor your application in minutes.

Try Sentry Free

Topics

Tracing
How Anthropic solved scaling log volume with Sentry

How Anthropic solved scaling log volume with Sentry

Listen to the Syntax Podcast

Of course we sponsor a developer podcast. Check it out on your favorite listening platform.

Listen To Syntax
© 2025 • Sentry is a registered Trademark of Functional Software, Inc.