vercel/next.js · error · Error

`unstable_isUnrecognizedActionError` can only be used on the

Error message

`unstable_isUnrecognizedActionError` can only be used on the client.

What it means

This error is thrown by the server-component stub of `unstable_isUnrecognizedActionError`. Next.js ships two implementations of the function: the real one in `unrecognized-action-error.ts` (client-only, checks `error instanceof UnrecognizedActionError`) and a `.react-server` variant in `navigation.react-server.ts` whose body unconditionally throws. The throw exists because detecting an unrecognized-action error requires the `UnrecognizedActionError` class, which is only meaningful in the browser bundle; calling it from a Server Component is a programming error.

Source

Thrown at packages/next/src/client/components/navigation.react-server.ts:4

import { ReadonlyURLSearchParams } from './readonly-url-search-params'

export function unstable_isUnrecognizedActionError(): boolean {
  throw new Error(
    '`unstable_isUnrecognizedActionError` can only be used on the client.'
  )
}

export { redirect, permanentRedirect } from './redirect'
export { notFound } from './not-found'
export { forbidden } from './forbidden'
export { unauthorized } from './unauthorized'
export { unstable_rethrow } from './unstable-rethrow'
export { ReadonlyURLSearchParams }

export const RedirectType = {
  push: 'push',
  replace: 'replace',
} as const

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Move the `unstable_isUnrecognizedActionError` call into a Client Component ('use client') so the import resolves to the real implementation in navigation.ts.
  2. If you must handle the error on the server, rethrow or re-surface it instead — the server never receives an UnrecognizedActionError, so the check is meaningless there.
  3. Audit import paths: ensure the file calling the function has the 'use client' directive at the top.

Example fix

// before (Server Component — throws)
import { unstable_isUnrecognizedActionError } from 'next/navigation'

export default async function Page() {
  try { await action() }
  catch (e) { if (unstable_isUnrecognizedActionError(e)) {} }
}

// after (Client Component)
'use client'
import { unstable_isUnrecognizedActionError } from 'next/navigation'

export function ActionButton() {
  try { await action() }
  catch (e) { if (unstable_isUnrecognizedActionError(e)) { window.location.reload() } }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure the calling file is a Client Component before importing.
// Check for the directive at the top of the file:
// 'use client'
// If absent, do not import unstable_isUnrecognizedActionError.

Type guard

// The real guard lives in navigation.ts (client). On the server,
// there is nothing to guard — avoid the import entirely.
function isClientContext(): boolean {
  return typeof window !== 'undefined'
}

Prevention

When it happens

Trigger: Importing `unstable_isUnrecognizedActionError` from `next/navigation` inside a Server Component, a Route Handler running in the RSC context, or any module that resolves the `.react-server` condition. The function executes its stub body at line 3-7, which always throws regardless of arguments.

Common situations: Copying a try/catch snippet from the docs into a Server Component instead of a Client Component; sharing an error-handling utility module between server and client files where the import resolves to the server variant; upgrading Next.js and not realizing the function is client-only.

Related errors


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