vercel/next.js · error · Error

Not a redirect error

Error message

Not a redirect error

What it means

`getRedirectTypeFromError` (redirect.ts:79) extracts the `push`/`replace` type from a `RedirectError`'s digest string. It guards with `isRedirectError(error)` and throws this literal `Error('Not a redirect error')` when the passed value is not a valid redirect error. The function is a narrow utility meant only for errors produced by `redirect()`/`permanentRedirect()`.

Source

Thrown at packages/next/src/client/components/redirect.ts:81

/**
 * Returns the encoded URL from the error if it's a RedirectError, null
 * otherwise. Note that this does not validate the URL returned.
 *
 * @param error the error that may be a redirect error
 * @return the url if the error was a redirect error
 */
export function getURLFromRedirectError(error: RedirectError): string
export function getURLFromRedirectError(error: unknown): string | null {
  if (!isRedirectError(error)) return null

  // Slices off the beginning of the digest that contains the code and the
  // separating ';'.
  return error.digest.split(';').slice(2, -2).join(';')
}

export function getRedirectTypeFromError(error: RedirectError): RedirectType {
  if (!isRedirectError(error)) {
    throw new Error('Not a redirect error')
  }

  return error.digest.split(';', 2)[1] as RedirectType
}

export function getRedirectStatusCodeFromError(error: RedirectError): number {
  if (!isRedirectError(error)) {
    throw new Error('Not a redirect error')
  }

  return Number(error.digest.split(';').at(-2))
}

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Guard with `isRedirectError(error)` before calling `getRedirectTypeFromError(error)`.
  2. Re-throw or ignore non-redirect errors in your catch block instead of assuming all caught errors are redirects.
  3. Verify the error originates from `redirect()`/`permanentRedirect()`, not `notFound()`/`unauthorized()` which use a different digest.

Example fix

// before
try { await action() }
catch (e) {
  const type = getRedirectTypeFromError(e) // throws if e isn't a redirect
}

// after
import { isRedirectError, getRedirectTypeFromError } from 'next/dist/client/components/redirect'
try { await action() }
catch (e) {
  if (isRedirectError(e)) {
    const type = getRedirectTypeFromError(e)
  } else { throw e }
}
Defensive patterns

Strategy: type-guard

Validate before calling

import { isRedirectError } from 'next/dist/client/components/redirect-error'
// Before calling getRedirectTypeFromError:
if (!isRedirectError(maybeErr)) {
  throw new TypeError('Expected a RedirectError')
}

Type guard

import { isRedirectError, type RedirectError } from 'next/dist/client/components/redirect-error'
function assertRedirectError(e: unknown): RedirectError {
  if (!isRedirectError(e)) throw new Error('Not a redirect error')
  return e
}

Try / catch

try {
  await action()
} catch (e) {
  if (isRedirectError(e)) {
    const type = getRedirectTypeFromError(e)
  } else {
    // not a redirect — handle or rethrow
    throw e
  }
}

Prevention

When it happens

Trigger: Passing an arbitrary caught error, a generic `Error`, `null`, or an error from a different Next.js subsystem (e.g. a notFound or unauthorized digest) into `getRedirectTypeFromError`. The `isRedirectError` check fails because the digest does not match the `NEXT_REDIRECT;type;url;status;` shape.

Common situations: A catch-all error handler that blindly pipes every caught error through redirect-extraction helpers without first narrowing; chaining `getURLFromRedirectError` and `getRedirectTypeFromError` assuming any error with a digest is a redirect; version mismatch where the digest format changed.

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/3b49f4082a3fd9e1. Report an issue: GitHub.