# Source maps on Vercel: why your production stack traces are unreadable

> A minified trace means the build never uploaded source maps. The auth token, the release name and the preview environment are the three things that are usually wrong.

The error arrives. You open it, and the stack trace looks like this:

```
TypeError: Cannot read properties of undefined (reading 'id')
  at t (/_next/static/chunks/4823-a91e2f.js:1:48210)
  at n (/_next/static/chunks/4823-a91e2f.js:1:52117)
  at o (/_next/static/chunks/main-app-7b2c1d.js:1:9932)
```

Three single-letter functions and a column number in a one-line file. It is
technically the truth and completely useless.

Sentry can un-minify this, but only if the build uploaded the source maps and
tagged them with the same release identifier the running code reports. When one
of those two halves is missing, you get exactly the output above, with no
error, no warning, and a green build.

## What has to line up

1. **`next build` generates source maps** for client and server bundles.
2. **The build uploads them** to Sentry, tagged with a release name.
3. **The running app reports the same release name** in every event.
4. **The maps are deleted** from the deployed output, so nobody can read your
   source by visiting `/_next/static/chunks/4823-a91e2f.js.map`.

`withSentryConfig` does 1, 2 and 4. Step 3 is on you, and it is the one that
silently breaks.

## The configuration

```ts
// next.config.ts
import { withSentryConfig } from "@sentry/nextjs/config"; // Sentry 11+
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // your config
};

export default withSentryConfig(nextConfig, {
  org: process.env.SENTRY_ORG,
  project: process.env.SENTRY_PROJECT,
  authToken: process.env.SENTRY_AUTH_TOKEN,
  silent: !process.env.CI,
  tunnelRoute: "/monitoring",
  sourcemaps: { deleteSourcemapsAfterUpload: true },
});
```

And the release, set identically everywhere the SDK is initialised:

```ts
// sentry.server.config.ts and sentry.edge.config.ts
release: process.env.VERCEL_GIT_COMMIT_SHA,

// src/instrumentation-client.ts: note the NEXT_PUBLIC_ prefix
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,
```

Vercel exposes both automatically; you do not set them yourself. The client one
needs the `NEXT_PUBLIC_` prefix because it has to be inlined into the browser
bundle at build time.

## The five things that are actually wrong

### 1. `SENTRY_AUTH_TOKEN` is not set in the build environment

The most common cause by a distance. The plugin cannot upload without a token,
and it does not fail the build when the token is missing: it logs a line you
did not read and carries on.

Set it in **Vercel > Settings > Environment Variables**, for **Production and
Preview**. `.env.local` is not enough: it is not in the repository, so the
Vercel build never sees it.

The token needs `project:releases` scope. Create it under Sentry Settings >
Auth Tokens, and treat it as a write credential for your whole organisation,
because that is what it is.

### 2. Preview deployments were forgotten

A very common shape: production traces are readable, preview traces are not.
Environment variables in Vercel are scoped per environment, and someone ticked
only Production. Every preview then builds without a token.

Tick Preview as well. If you use it, tick Development too.

### 3. The release names do not match

The build uploads maps under one name and the running app reports another, so
Sentry has maps and events that never meet. Symptoms: the release exists in
Sentry with artifacts attached, but issues show minified frames.

Check the issue's **Tags > release** and compare it with the release listed
under Sentry's Releases page. They must be byte-identical. Two ways this breaks:

- The client uses `VERCEL_GIT_COMMIT_SHA` (undefined in the browser) instead of
  `NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA`.
- Someone hardcoded `release: "1.0.0"` in one config and left the others on the
  commit SHA.

### 4. Server-side traces are minified but client ones are fine

Next.js does not emit server source maps in production by default. The Sentry
plugin turns them on for you; if you have an explicit
`productionBrowserSourceMaps` or a custom webpack config that overrides
`devtool`, you can end up with client maps only. Remove the override and let
the plugin manage it.

### 5. The maps uploaded, but to the wrong project

`SENTRY_ORG` and `SENTRY_PROJECT` point at project A, the DSN points at project
B. Everything succeeds and nothing lines up. Compare the DSN's project id with
the project slug in your environment variables.

## Verifying, without waiting for a real error

Make the build noisy first:

```bash
SENTRY_AUTH_TOKEN=... SENTRY_ORG=... SENTRY_PROJECT=... bun run build
```

With `silent: false` you should see the plugin resolve your org and project,
create a release, and upload a number of artifacts. Zero artifacts means the
upload did not happen; read the line above it.

Then check in Sentry: **Releases > your commit SHA > Artifacts**. If files are
listed there and issues are still minified, the problem is release-name
mismatch (cause 3), not upload.

Finally, deploy a throwaway route that throws, hit it, and confirm the issue
shows a real file path and line number. Delete the route.

## Do not commit the token

`SENTRY_AUTH_TOKEN` is a build-time secret with write access to your Sentry
organisation. It must never appear in `next.config.ts` as a literal, never be
prefixed `NEXT_PUBLIC_`, and never be read by application code. It belongs in
Vercel's environment variables and in your local `.env.local`, which is
gitignored. If it ever lands in a commit, revoke it in Sentry immediately:
rotating is thirty seconds and there is no reason to hesitate.

---

Agentic Boilerplate: A Next.js repo your agent already knows. $99 once. Lifetime access and updates.

- Site map for agents: https://agenticboilerplate.com/llms.txt
- Public API: https://agenticboilerplate.com/openapi.json
- Contact: agenticstudio@gmail.com
