@clerk/nextjs
semver
>=7.0.0postconditions6functions5last verified2026-06-25coverage score100%Postconditions: what we check
- getToken · get-token-ssr-not-handlederrorWhenuseAuth().getToken called during server-side rendering (SSR) or in any non-browser environment where window is undefined. In v7+, this throws ClerkRuntimeError with code `clerk_runtime_not_browser` instead of returning undefined as it did in v5/v6. Code paths that previously guarded with `if (token === undefined)` will now throw uncaught at SSR.Throws
ClerkRuntimeError (code: clerk_runtime_not_browser)Required handlingMUST either (a) call useAuth().getToken only inside useEffect or a click handler so it runs browser-side, or (b) wrap in try-catch and detect ClerkRuntimeError with code `clerk_runtime_not_browser`. The token is not available during SSR — design the component to skip the call when window is undefined, or migrate to server-side auth() for SSR token needs.costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - getToken · get-token-offline-not-handlederrorWhenuseAuth().getToken called when the Clerk client is offline (no network connectivity to Clerk's auth servers). In v7+, this throws ClerkOfflineError instead of returning `null` as it did in v5/v6. Code paths that previously guarded with `if (token === null) return` will now throw uncaught when the user's network drops or the Clerk backend is briefly unreachable. Particularly common in PWAs, mobile web wrappers, and any flow that fetches tokens during retry loops.Throws
ClerkOfflineErrorRequired handlingMUST wrap useAuth().getToken() in try-catch and handle ClerkOfflineError separately from authentication errors. Typical pattern: on ClerkOfflineError, show a "Reconnecting..." UI and retry with exponential backoff. Do NOT sign the user out on this error — their session is still valid, just temporarily unreachable. Code that previously checked `if (!token)` will silently miss this branch and crash the calling component.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - clerkMiddleware · middleware-missing-encryption-keyerrorWhenclerkMiddleware() invoked at runtime with secretKey supplied (via env var CLERK_SECRET_KEY or options.secretKey) but CLERK_ENCRYPTION_KEY is not configured. v6 silently used an in-memory generated fallback; v7 throws explicitly because the fallback created cross-request token decryption failures in serverless deployments.Throws
Error: Missing CLERK_ENCRYPTION_KEY environment variableRequired handlingMUST set CLERK_ENCRYPTION_KEY in environment variables for any deployment using a custom secretKey. Generate a strong random key (e.g. `openssl rand -hex 32`) and store it alongside CLERK_SECRET_KEY. The key must be stable across all server instances — rotating it invalidates all existing session tokens. Without it, EVERY request through clerkMiddleware throws and the app returns 500.costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - protect · protect-server-action-status-code-changedwarningWhenauth.protect() called inside a Next.js server action ("use server" file or `'use server'` inline directive). In v6 and earlier, an unauthenticated request to a server action returned HTTP 404. In v7+, it returns HTTP 401. Any client-side error handler, monitoring rule, or test that previously branched on `response.status === 404` to detect "logged out" will silently miss the unauthenticated case after upgrade and surface confusing UI behavior (typically: the action appears to fail without redirecting to sign-in).Throws
HTTP 401 (auth.protect rejects unauthenticated server-action callers)Required handlingMUST audit every call site that compared response.status to 404 (fetch responses, useTransition error handlers, server-action wrappers like `useActionState`) and update the comparison to 401. Pattern: replace `if (res.status === 404) signOut()` with `if (res.status === 401) signOut()`. Generic catch blocks that treated any error as "auth failure" continue to work, but status-aware branches MUST be migrated.costmediumin proddegraded serviceusers seeauthentication failurevisibilityvisible - useUser · use-user-initial-auth-state-removedwarningWhenuseUser() or useAuth() called with the legacy `initialAuthState` option (e.g. `useUser({ initialAuthState: ... })`). In v7 the option is removed; the hook silently ignores it and the initial state must be passed at the ClerkProvider boundary via `initialState`. The refactor to `useSyncExternalStore` changed how SSR/CSR state is rehydrated — any app that passed `initialAuthState` per-hook will flash a logged-out state on hydration before the real state catches up, producing a hydration mismatch warning and a UI flicker.Throws
Silent no-op on v7 (option ignored); React hydration mismatch warning at runtimeRequired handlingMUST migrate the initial state to `<ClerkProvider initialState={...}>` at the app root (typically in app/layout.tsx). Remove every `initialAuthState` argument from useUser/useAuth call sites. Audit shared component libraries that may still pass the option through.costlowin prodsilent failureusers seedegraded performancevisibilityvisible - currentUser · current-user-pending-session-default-changederrorWhencurrentUser() called in a v7+ codebase without explicitly setting the `treatPendingAsSignedOut` option. The new default treats users in a "pending" verification state (MFA pending, email-verification pending, organization-selection pending) as signed-OUT — meaning currentUser() returns `null` for these users. In v6 and earlier, pending users were returned with their User object intact, and downstream guards typically gated access by checking specific verification fields. Code that previously relied on the User object being non-null for pending users (e.g. to redirect them to a verification page) now incorrectly redirects them to the sign-IN page.Throws
Silent behavior change: currentUser() returns null for pending users (was: User object)Required handlingMUST either (a) pass `treatPendingAsSignedOut: false` to currentUser() to restore v6 behavior for the existing verification flow, OR (b) refactor the verification flow to handle pending users at the ClerkProvider/middleware layer (recommended). Audit every currentUser() call site that branched on `user.unsafeMetadata` / `user.publicMetadata.pendingVerification` or similar — these branches will silently dead-code in v7.costmediumin prodsilent failureusers seeauthentication failurevisibilityvisible
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
Need a different package?
Request a profile