Issue with Next JS SSG preview mode and `next-i18next` package causing 500 error on Netlify

6 replies
Last updated: Dec 16, 2021
Hi,I’m getting
Not authenticated - preview not available eval @ next-sanity.esm.js?c596:159
when in Preview Mode (Next JS SSG).

But actually, the live preview DOES work (Studio Pane and external window) – but only on localhost. As soon as I try in production I only ever get an Error 500…

Also, when I try to (unsuccessfully) access the Preview in production and the relevant Cookie(s) is/are set, it in turn leads to a 500 that persists, even when NOT in preview mode.
When I delete these Cookies, “Normal Mode” functions perfectly again…

Anyone experienced sth. similar or has any ideas why it would work just fine locally but not in production?

It’s a public dataset, I’ve checked all the relevant CORS settings and the environment variables are the same (if I didn’t miss anything). I tried hosting the frontend on Netlify and on Vercel – makes no difference.
AI Update

This is a frustrating issue that often comes down to environment-specific differences between local and production. Based on your symptoms (works locally, 500 errors in production, cookie-related persistence), here are the most likely causes:

1. Token Authentication Issues

The "Not authenticated - preview not available" error typically means your preview token isn't being properly authenticated in production. Even though your dataset is public, Draft Mode requires an authenticated token to fetch draft content using the previewDrafts perspective.

Check:

  • Verify your SANITY_API_READ_TOKEN (or SANITY_API_TOKEN) environment variable is set correctly in production (Netlify/Vercel)
  • Ensure the token has proper read permissions for your dataset
  • The token should work for the previewDrafts perspective, not just published content
  • Make sure it's set as a secret (server-side) environment variable, not a public one

The persistent 500 error when Draft Mode cookies are set suggests the cookies are causing issues with your server-side rendering. Next.js Draft Mode uses cookies (__prerender_bypass or __next-draft-mode depending on version) to track preview state.

Common issues:

  • Cookies set with incorrect domain attributes
  • Cookie security settings (SameSite, Secure) not compatible with your production setup
  • The server-side code encountering errors when trying to process the draft mode state

Solution: Add an exit Draft Mode route so users can clear problematic cookies:

// app/api/disable-draft/route.ts
import { draftMode } from 'next/headers'

export async function GET() {
  draftMode().disable()
  return new Response('Draft mode disabled')
}

Visit https://your-site.com/api/disable-draft to clear the cookies manually when things break.

If your Studio and Next.js site are on different domains, browsers may block third-party cookies, breaking Draft Mode authentication.

Check:

  • Are you accessing preview from the Studio's Presentation tool on a different domain?
  • Try accessing the preview directly on your production domain (not embedded in Studio)
  • Verify CORS settings in your Sanity project (manage.sanity.io → Settings → API → CORS Origins) include your production domain with "Allow credentials" enabled
  • Test in an incognito window to rule out browser extension interference

4. API Route Configuration and Errors

Your Draft Mode enable/disable API routes might be encountering errors in production that don't occur locally.

Verify:

  • Your /api/draft (or similar) route handler is deployed and accessible in production
  • It's properly enabling draft mode using draftMode().enable() from next/headers
  • The route validates your preview secret/token before enabling
  • Check your production logs (Vercel Functions tab or Netlify Functions logs) for the actual error when the 500 occurs

Example Draft Mode enable route:

// app/api/draft/route.ts
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const secret = searchParams.get('secret')
  const slug = searchParams.get('slug') || '/'

  // Validate secret
  if (secret !== process.env.SANITY_REVALIDATE_SECRET) {
    return new Response('Invalid token', { status: 401 })
  }

  draftMode().enable()
  redirect(slug)
}

5. Environment Variable Mismatch

Double-check these environment variables are set identically in both local and production:

SANITY_API_READ_TOKEN=<your-token-with-read-permissions>
NEXT_PUBLIC_SANITY_PROJECT_ID=<your-project-id>
NEXT_PUBLIC_SANITY_DATASET=<your-dataset>
SANITY_REVALIDATE_SECRET=<your-secret-for-draft-mode-activation>

The SANITY_API_READ_TOKEN especially must be available server-side in production. On Vercel/Netlify, ensure you've set these in the dashboard and redeployed after adding them (adding env vars doesn't auto-redeploy).

Critical Debugging Steps

  1. Check production logs FIRST - This will save you hours. On Vercel, go to your deployment → Functions tab. On Netlify, check the Functions logs. The 500 error will have a stack trace showing exactly what's failing.

  2. Test your API route directly - Visit https://your-site.com/api/draft?secret=YOUR_SECRET&slug=/ in production to see if it errors or successfully enables draft mode.

  3. Inspect cookies - In production, open DevTools → Application → Cookies and check if the Draft Mode cookies are being set with proper attributes (domain, path, secure, samesite).

  4. Test without Presentation tool - Try enabling Draft Mode by visiting the API route directly (not through Studio's Presentation tool) to isolate whether it's a Studio integration issue or a Draft Mode issue.

  5. Try a fresh deployment - Sometimes stale build cache or function deployments cause issues. Trigger a fresh deploy with cleared cache.

Most Likely Culprit

In my experience, the most common cause is the SANITY_API_READ_TOKEN not being properly set in production environment variables. Since it works locally, you likely have it in your .env.local file, but it might be:

  • Missing entirely from Vercel/Netlify
  • Named differently in production
  • Not available to the serverless functions

The second most common issue is the Draft Mode API route itself returning a 500 because it can't access environment variables or is encountering an error when trying to validate the secret. Check your production logs first - they'll give you the exact error message and point you directly to the problem.

Hi, here’s an overview 🙃

S = Sanity, 
N = NextJS, 
prod. = deployed / hosted on Netlify

S (local) + N (local) = 🟢* 
// works perfectly, but "Not authenticated" from next-sanity.esm.js

S (local) + N (prod.) = 🔴
// 500 Internal Server Error for N

S (prod.) + N (local) = 🟠 
// displays page, but doesn't apply changes live, no error 500, no "Not authenticated" error

S (prod.) + N (prod.) = 🔴
// 500 Internal Server Error for N

Hi, here’s an overview 🙃

S = Sanity, 
N = NextJS, 
prod. = deployed / hosted on Netlify

S (local) + N (local) = 🟢* 
// works perfectly, but "Not authenticated" from next-sanity.esm.js

S (local) + N (prod.) = 🔴
// 500 Internal Server Error for N

S (prod.) + N (local) = 🟠 
// displays page, but doesn't apply changes live, no error 500, no "Not authenticated" error

S (prod.) + N (prod.) = 🔴
// 500 Internal Server Error for N

Thank you for clarifying! I'll spend some time on this one today.
Thanks, but please don’t bother :-) I “fixed” it just now. In the end it came down to the
next-i18next
package causing problems, but only in the specific combination of either SSR or SSG-in-preview-mode on Netlify (Vercel was fine either way). This lead to an error 500 that persisted as long as the cookie was set. I’ve since switched to the
next-translate
package as I just couldn’t get
next-i18next
to work on Netlify.
Thanks, but please don’t bother :-) I “fixed” it just now. In the end it came down to the
next-i18next
causing problems, but only in the specific combination of either SSR or SSG-in-preview-mode on Netlify (Vercel was fine either way). This lead to an error 500 that persisted as long as the cookie was set. I’ve since switched to the
next-translate
package as I just couldn’t get
next-i18next
to work on Netlify.
Glad you got it figured out! Thanks so much for sharing your solution!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?