# next.js correction pack · for projects on next@^16
<!--
     Stale Priors Index · Unattended Works · https://github.com/SamAndrzejewski

     GENERATED FILE — DO NOT EDIT BY HAND. Your edit will be destroyed by the next build.
     Rebuild:  node tools/build-corrections.mjs
     Sources:  data/next.js/facts.json  (the corrections, each verified against a primary source)
               data/next.js/*.json      (the evidence: reproduced model failures)

     Latest next.js: 16.3.4 · verified 2026-09-02
     Coverage: Claude Fable 5, Claude Opus 5, Claude Sonnet 5 — next.js/v1 (2026-08-31), next.js/v2-a (2026-09-02), next.js/v2-b (2026-09-02), next.js/v2-c (2026-09-02), next.js/v2-d (2026-09-02), next.js/v3-a (2026-09-02), next.js/v3-b (2026-09-02), next.js/v3-c (2026-09-02), next.js/v3-d (2026-09-02), next.js/v3-e (2026-09-02), next.js/v3-f (2026-09-02)

     Paste into CLAUDE.md / AGENTS.md / .cursorrules if your project uses next@^16.
     Do NOT use if you are pinned to next@15 or earlier.
-->

## What we actually measured

3 Claude models were asked for idiomatic next.js code with no tools, purely from training knowledge. 21 reproduced failures across 13 runs, each verified against the release that broke the belief.

| Model | Stated cutoff | next.js version attribution stops | Lag inside the window |
|---|---|---|---|
| Claude Sonnet 5 | 2026-01 | 15.0.0 · 2024-10-21 | ~15 months |
| Claude Opus 5 | 2026-05 | 16.0.0 · 2025-10-22 | ~7 months |
| Claude Fable 5 | 2026-01 | 16.0.0 · 2025-10-22 | ~3 months |

A recent cutoff is not a defence. Every model here loses track of this library's release history well before the date it states as its own cutoff, and the stopping points cluster far tighter than the cutoffs do.

Read that column precisely. It is the newest next.js release whose contents the model can correctly **attribute to that release** — not the newest next.js feature it knows. Past that point a model will often write working code with a newer API while naming the wrong release for it, and that guess runs *early* — it names a release older than the one that shipped the feature. So the question this pack answers is not "does the model know this API" but "can it be trusted about which version the API arrived in" — which is the question that matters when you are pinned to a version.

Latest next.js is **16.3.4** (verified 2026-09-02). Separately from the corrections below, 2 of 13 runs recorded a version fact — the model named a current next.js version from memory and was behind. If a model states a version without checking, assume it is behind and check the registry.

## How to read an entry

Every entry ends with a *Reproduced against* line. Where it names models, we have the generated code that got it wrong, dated, with the model's own words in the run write-up. Where it says no model yet, the correction is verified from the release notes but nothing has been probed for it — it is a fix, not a measurement, and the pack says so rather than blurring the two.

The section an entry sits in is the worst case if you act on the stale belief. The severity in brackets after a model's name is what that particular model's output actually did, which can be milder — a model can hold the wrong belief and still, on the day, write code that runs.

## The corrections

### Breaks the build, or throws at runtime

Act on the stale belief here and the code does not run. Fix these first.

#### `revalidateTag`

**Behaviour changed in next.js 16.0.0** (2025-10-22)

`revalidateTag` takes two arguments. The single-argument form is deprecated in 16.0.0 and documented as producing a TypeScript error, so on a TypeScript project — where `next build` type-checks by default — it fails the build. Use `revalidateTag(tag, profile)` for content that tolerates eventual consistency, `updateTag(tag)` in a Server Action when the user must see their own write immediately, and `refresh()` to refresh uncached data without touching the cache.

*The stale belief:* That `revalidateTag('products')` is the current call signature.

```ts
// Stale
revalidateTag('products')

// Current
revalidateTag('products', 'max')   // 'max' | 'hours' | 'days' | { expire: 3600 }
updateTag('products')              // Server Actions only: read-your-writes
refresh()                          // Server Actions only: refresh uncached data
```

> This is the most reliably reproduced entry in the whole Index: every model tested writes the one-argument form in generated code, and two of the three can state the two-argument signature correctly when asked directly.

*Reproduced against: **Claude Fable 5** (S1), **Claude Opus 5** (S1), **Claude Sonnet 5** (S1) — next.js/v1, 2026-08-31.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25 · [Next.js 16 release announcement](https://nextjs.org/blog/next-16) · 2025-10-21

#### custom webpack config

**Default changed in next.js 16.0.0** (2025-10-22)

Turbopack is stable and the default for both `next dev` and `next build`. `--turbopack` is no longer needed; `--webpack` is the opt-out. A project carrying a custom webpack config now fails the build unless it opts out.

*The stale belief:* That webpack is the default bundler and Turbopack is opt-in behind `--turbopack`.

```jsonc
// Stale
"dev": "next dev --turbopack"

// Current
"dev": "next dev"
"build": "next build"          // Turbopack
"build:webpack": "next build --webpack"   // opt out
```

> `experimental.turbopack` as a config location moved to a top-level `turbopack` key.

*Reproduced against: **Claude Sonnet 5** (S4) — next.js/v1, 2026-08-31.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### next lint

**Removed in next.js 16.0.0** (2025-10-22)

The `next lint` command was removed — a `package.json` script that calls it fails. Call ESLint or Biome directly. `next build` no longer runs linting either, and the `eslint` option in the Next.js config file is removed.

*The stale belief:* That `next lint` is the project lint script and that `next build` lints for you.

```jsonc
// Stale
"lint": "next lint"

// Current
"lint": "eslint"
```

> Codemod: `npx @next/codemod@canary next-lint-to-eslint-cli .`. `@next/eslint-plugin-next` now defaults to ESLint flat config.

*Reproduced against: **Claude Sonnet 5** (S1) — next.js/v1, 2026-08-31.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### parallel route default.js

**New requirement in next.js 16.0.0** (2025-10-22)

Every parallel route slot requires an explicit `default.js`. Builds fail without one. To keep the previous behaviour, create a `default.js` per slot that returns `null` or calls `notFound()`.

*The stale belief:* That `default.js` is optional and its absence only causes a runtime 404 on reload — the pre-16 behaviour.

```ts
// app/@modal/default.tsx
export default function Default() { return null }
```

*Reproduced against: **Claude Fable 5** (S2) — next.js/v1, 2026-08-31.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### AMP support (next/amp, useAmp, config.amp)

**Removed in next.js 16.0.0** (2025-10-22)

All AMP APIs and configuration were removed: the `amp` config key, `next/amp` imports including `useAmp`, and `export const config = { amp: true }`.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### async request APIs

**Removed in next.js 16.0.0** (2025-10-22)

The synchronous-access compatibility period is over. `cookies()`, `headers()`, `draftMode()`, `params` and `searchParams` are async only — 15.x allowed sync access with a warning, 16.0.0 removed it.

```ts
const { slug } = await params
const cookieStore = await cookies()
```

> Also newly async in 16.0.0 and much less well known: the props passed to `opengraph-image`, `twitter-image`, `icon` and `apple-icon` generating functions, and the `id` passed to a `sitemap` function by `generateSitemaps`. `generateImageMetadata` still receives synchronous `params`.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### `serverRuntimeConfig / publicRuntimeConfig`

**Removed in next.js 16.0.0** (2025-10-22)

Both were removed. Use environment variables instead.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

### Runs, but is silently wrong

Nothing errors. The behaviour is simply not what a model trained earlier will tell you.

#### `experimental.clientSegmentCache`

**Removed in next.js 16.0.3** (2025-11-13)

`experimental.clientSegmentCache` no longer exists. It was `boolean | 'client-only'`, defaulted to `true`, and was removed one day after 16.0.2 — per-segment prefetching is now unconditional and has no on/off switch under any name. Because an unrecognised key under `experimental` only **warns** (the build exits only for unrecognised keys under `images`, and for two named Turbopack keys), setting it looks accepted and does nothing at all. If the goal is fewer prefetch requests per link, the current lever is `experimental.prefetchInlining` (16.2.0); if it is no prefetching, it is `<Link prefetch={false}>`.

*The stale belief:* That per-segment prefetching can be switched off with `experimental: { clientSegmentCache: false }` to get one whole-tree prefetch request per link. It was true up to 16.0.2 and has been silently inert since 16.0.3.

**The code below needs next.js 16.2.0 or later.** Between 16.0.3 and 16.2.0 this correction does not apply — see the note.

```ts
// Stale
experimental: { clientSegmentCache: false }

// Current
experimental: { prefetchInlining: true }
```

> Bisected in the published packages: declared in `dist/server/config-shared.d.ts` at 15.5.0, 16.0.0 and 16.0.2, absent from 16.0.3 onward through 16.3.4, with no renamed replacement (no config key in 16.3.4 contains 'segment'). This is a removal that shipped in a **patch**, one day after the release that still had it.

*Reproduced against: **Claude Fable 5** (S2), **Claude Opus 5** (S2), **Claude Sonnet 5** (S2) — next.js/v2-a, 2026-09-02; next.js/v3-a, 2026-09-02; next.js/v3-c, 2026-09-02.*

Source: [next 16.0.2 published package — the key still exists](https://unpkg.com/next@16.0.2/dist/server/config-shared.d.ts) · 2025-11-12 · [next 16.0.3 published package — the key is gone one day later](https://unpkg.com/next@16.0.3/dist/server/config-shared.d.ts) · 2025-11-13 · [next 16.3.4 published package — why the dead key is silent rather than fatal](https://unpkg.com/next@16.3.4/dist/server/config.js) · 2026-08-31

#### experimental.ppr / export const experimental_ppr

**Removed in next.js 16.0.0** (2025-10-22)

The route-segment opt-in was removed: `export const experimental_ppr = true` is read nowhere in 16.x, so a page that still exports it is simply ignored. The **config key was not removed** — `experimental: { ppr }` is still declared on `NextConfig`, still accepted by the config validator, and still honoured by `checkIsAppPPREnabled` at every 16.x release including 16.3.4. The trap is the combination: `experimental: { ppr: 'incremental' }` validates cleanly and then enables partial prerendering for **no route at all**, because `checkIsRoutePPREnabled` returns `false` for anything that is not a boolean and there is no longer a per-route export to consult. Nothing breaks; PPR just silently never happens. Configure partial prerendering with the top-level `cacheComponents: true`, which is also the new name of `experimental.dynamicIO`.

*The stale belief:* That partial prerendering is enabled through the `experimental.ppr` flag plus a per-route `export const experimental_ppr = true`. The flag half still validates; the per-route half does nothing.

```ts
// Stale
// next.config.ts — validates, and enables PPR for zero routes
experimental: { ppr: 'incremental' }
// app/page.tsx — read by nothing in 16.x
export const experimental_ppr = true

// Current
// next.config.ts
const nextConfig: NextConfig = { cacheComponents: true }
```

> Do not tell readers this config key breaks the build — it does not, at any 16.x release. Next.js's own upgrade guide, shipped inside the package at 16.3.4 as `dist/docs/01-app/02-guides/upgrading/version-16.md`, states that 16 "removes the experimental Partial Prerendering (PPR) flag and configuration options"; the same tarball ships `dist/server/lib/experimental/ppr.js` implementing it and a `configSchema` that accepts it. Verified by executing the shipped validator: at both 16.0.0 and 16.3.4, `experimental.ppr` set to `'incremental'` and to `true` are ACCEPTED, while the poison controls `experimental.pprXYZ` (unrecognized_keys) and `experimental.ppr: 'nope'` (invalid_union) are rejected — so the check can fail. The Suspense structure around a dynamic subtree is unchanged; models generally get that part right.

*Reproduced against: **Claude Opus 5** (S1), **Claude Sonnet 5** (S1) — next.js/v1, 2026-08-31.*

Source: [Next.js docs — Upgrading: Version 16 (states a removal the shipped package contradicts)](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25 · [next 16.3.4 shipped package — dist/server/lib/experimental/ppr.d.ts](https://unpkg.com/next@16.3.4/dist/server/lib/experimental/ppr.d.ts) · 2026-08-31 · [next 16.3.4 shipped package — NextConfig still declares experimental.ppr](https://unpkg.com/next@16.3.4/dist/server/config-shared.d.ts) · 2026-08-31 · [next 16.0.0 shipped package — the release said to have removed it still declares experimental.ppr](https://unpkg.com/next@16.0.0/dist/server/config-shared.d.ts) · 2025-10-22

#### `middleware.ts`

**Renamed in next.js 16.0.0** (2025-10-22)

`middleware.ts` is renamed to `proxy.ts`, and the named export `middleware` to `proxy`. The old file still works and warns; removal is planned. The rename shipped in 16.0.0 — not 15.5 — so renaming the file on a 15.x project means nothing picks it up and the route gate silently stops running.

*The stale belief:* That the route gate lives in `middleware.ts`, or that the rename landed in 15.5.

```ts
// Stale
// middleware.ts
export function middleware(request: NextRequest) { /* ... */ }

// Current
// proxy.ts
export function proxy(request: NextRequest) { /* ... */ }
export const config = { matcher: ['/dashboard/:path*'] }
```

> Two things models do not tell you: the `proxy` runtime is nodejs and cannot be configured (keep `middleware.ts` if you need the edge runtime), and `skipMiddlewareUrlNormalize` is now `skipProxyUrlNormalize`.

*Reproduced against: **Claude Opus 5** (S4), **Claude Sonnet 5** (S3) — next.js/v1, 2026-08-31.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### `experimental.prefetchInlining`

**Added in next.js 16.2.0** (2026-03-18)

Next.js 16 prefetches **per segment**: hovering one `<Link>` issues a separate request for each segment of the target route tree, which makes shared layouts cacheable across sibling routes but multiplies request volume. `experimental.prefetchInlining` bundles every segment of a route into a single prefetch response — one request per link — at the cost of duplicating shared layout data across responses. There is no `<Link>`-level prop for this; it is a config flag.

*The stale belief:* That the number of prefetch requests per link is not configurable, and that the only lever is turning prefetching off with `prefetch={false}`.

```ts
experimental: { prefetchInlining: true }
```

> Verified in the published packages: `prefetchInlining`, `cachedNavigations` and `appNewScrollHandler` are all absent from `dist/server/config-shared.d.ts` at 16.1.7 and present at 16.2.0 and 16.3.4. Still experimental at 16.3.4.

*Reproduced against: **Claude Opus 5** (S2) — next.js/v3-e, 2026-09-02.*

Source: [Next.js 16.2 release post — experimental.prefetchInlining](https://nextjs.org/blog/next-16-2) · 2026-03-18 · [next 16.3.4 published package — the experimental config key](https://unpkg.com/next@16.3.4/dist/server/config-shared.d.ts) · 2026-08-31

#### ImageResponse default font

**Default changed in next.js 16.2.0** (2026-03-18)

The default typeface used by `ImageResponse` when no font is supplied changed from Noto Sans to **Geist Sans**. The bundled default font file is `Geist-Regular.ttf`. Generated OG images render in Geist unless a `fonts` option says otherwise.

*The stale belief:* That an OG image with no `fonts` option renders in Noto Sans (the default from `@vercel/og`'s original bundle).

> Bisected in the published packages: `dist/compiled/@vercel/og/index.node.js` loads `noto-sans-v27-latin-regular.ttf` at 16.1.7 and `Geist-Regular.ttf` at 16.2.0 — two days apart. The same release made `ImageResponse` 2x-20x faster and widened CSS/SVG coverage.

*Reproduced against: **Claude Opus 5** (S2) — next.js/v2-a, 2026-09-02.*

Source: [Next.js 16.2 release post — Faster ImageResponse](https://nextjs.org/blog/next-16-2) · 2026-03-18 · [next 16.2.0 published package — the bundled default font](https://unpkg.com/next@16.2.0/dist/compiled/@vercel/og/index.node.js) · 2026-03-18 · [next 16.1.7 published package — the same line two days earlier](https://unpkg.com/next@16.1.7/dist/compiled/@vercel/og/index.node.js) · 2026-03-16

#### Link transitionTypes

**Added in next.js 16.2.0** (2026-03-18)

`next/link` accepts a `transitionTypes` prop — an array of strings passed to React's `addTransitionType` during the navigation Transition, so a View Transition can be styled differently per navigation. It is an App Router feature: the **Pages Router `Link` destructures the prop away and ignores it silently**, so a shared link component works in both routers without warnings. It is never forwarded to the underlying `<a>`, in either router, so it produces no unknown-DOM-attribute warning; in development a non-array value throws a prop-type error.

*The stale belief:* That `<Link>` has no per-navigation view-transition prop, so an unrecognised `transitionTypes` prop is spread onto the `<a>` element and React warns about an unknown DOM attribute.

```tsx
<Link href="/about" transitionTypes={['slide']}>About</Link>
```

> Verified in the published packages: absent from `dist/client/app-dir/link.d.ts` at 16.1.7, present at 16.2.0. At 16.3.4 the Pages Router `dist/client/link.js` destructures `transitionTypes` out of `restProps` and lists it in its dev-only prop guard, while the App Router `dist/client/app-dir/link.js` forwards it into `dispatchNavigateAction`.

*Reproduced against: **Claude Opus 5** (S2) — next.js/v2-a, 2026-09-02.*

Source: [Next.js 16.2 release post — transitionTypes Prop for next/link](https://nextjs.org/blog/next-16-2) · 2026-03-18 · [next 16.3.4 published package — the Pages Router Link discards the prop](https://unpkg.com/next@16.3.4/dist/client/link.js) · 2026-08-31 · [next 16.1.7 published package — the prop does not exist yet](https://unpkg.com/next@16.1.7/dist/client/app-dir/link.d.ts) · 2026-03-16

#### `images.maximumDiskCacheSize`

**Added in next.js 16.1.7** (2026-03-16)

The optimized-image disk cache is bounded, and by default the bound is **50% of the free space on the volume holding the cache directory**, measured once at startup with `fs.statfs`. Set `images.maximumDiskCacheSize` to a byte count to cap it, or to `0` to disable disk caching entirely. When the cache exceeds the limit, least-recently-used optimized images are evicted until it is under the limit.

*The stale belief:* That the optimized-image cache in `.next/cache/images` grows without limit and the only controls are `minimumCacheTTL` or a custom cache handler.

```ts
images: { maximumDiskCacheSize: 1_000_000_000 } // 1 GB; 0 disables the disk cache
```

> Shipped in a **patch** release, 16.1.7, two days before the 16.2.0 minor. Verified in the published packages: `maximumDiskCacheSize` is absent from `imageConfigDefault` at 16.1.6 and present (as `undefined`) at 16.1.7, where `dist/server/lib/disk-lru-cache.external.js` first appears. An unrecognised key under `images` is fatal, not a warning: `normalizeNextConfigZodErrors` sets `shouldExit` for any issue whose path starts at `images`, so a guessed name such as `images.maximumCacheSize` exits the build.

*Reproduced against: **Claude Opus 5** (S1) — next.js/v2-a, 2026-09-02.*

Source: [Next.js docs — Image component, maximumDiskCacheSize](https://nextjs.org/docs/app/api-reference/components/image) · 2026-09-02 · [next 16.3.4 published package — the default sizing](https://unpkg.com/next@16.3.4/dist/server/lib/disk-lru-cache.external.js) · 2026-08-31 · [next 16.1.7 published package — the key enters imageConfigDefault](https://unpkg.com/next@16.1.7/dist/shared/lib/image-config.js) · 2026-03-16

#### `images.maximumResponseBody`

**Added in next.js 16.1.5** (2026-01-26)

The default image loader refuses a source image whose response body exceeds **50 MB** (`maximumResponseBody: 50000000`). The optimizer streams the upstream response and, once the running total passes the limit, throws an image error carrying HTTP **413** — the image 404s/413s rather than being optimized. Lower it (e.g. `5_000_000`) on memory-constrained servers.

*The stale belief:* That `next/image` will fetch and optimize a remote source image of any size, and that the only failure mode for a large image is slowness or an out-of-memory crash.

```ts
images: { maximumResponseBody: 5_000_000 }
```

> The official docs' version-history table dates this to **v16.1.2**; the published packages contradict it by three patch releases. There is no occurrence of `maximumResponseBody` in 16.1.2's `image-config.js`, `config-shared.js`, `config-schema.js` or `image-optimizer.js`, nor in 16.1.4; 16.1.5 has it in `imageConfigDefault` and three times in `image-optimizer.js`. This is the second time vendor release material has been wrong about its own release in this dataset (better-auth 1.1.0, JOURNAL/027) and the first time the error is in a docs version table rather than a changelog.

*Reproduced against: **Claude Opus 5** (S2) — next.js/v3-e, 2026-09-02.*

Source: [Next.js docs — Image component, maximumResponseBody](https://nextjs.org/docs/app/api-reference/components/image) · 2026-09-02 · [next 16.3.4 published package — the limit is enforced while streaming](https://unpkg.com/next@16.3.4/dist/server/image-optimizer.js) · 2026-08-31 · [next 16.1.5 published package — the release the key actually appears in](https://unpkg.com/next@16.1.5/dist/shared/lib/image-config.js) · 2026-01-26 · [next 16.1.4 published package — absent one release earlier](https://unpkg.com/next@16.1.4/dist/shared/lib/image-config.js) · 2026-01-19

#### `images.minimumCacheTTL`

**Default changed in next.js 16.0.0** (2025-10-22)

The default changed from 60 seconds to 14400 seconds (4 hours). Nothing errors; images just revalidate far less often than a model trained on 15.x will tell you.

*The stale belief:* That the default image cache TTL is 60 seconds.

```ts
images: { minimumCacheTTL: 60 }   // if you need the old behaviour back
```

*Reproduced against: **Claude Sonnet 5** (S2) — next.js/v1, 2026-08-31.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### catchError (next/error)

**Added in next.js 16.2.0** (2026-03-18)

`next/error` exports `catchError`, which wraps a fallback component into a component-level error boundary usable anywhere in a Client Component tree — finer-grained than the route-level `error.js` convention. Its fallback receives the call-site props plus an `ErrorInfo` second argument (`{ error, reset, retry }`). Prefer it over a hand-rolled React class boundary: Next's own boundary re-throws the framework's control-flow errors, so `redirect()` and `notFound()` still work inside it, while a naive user boundary catches them and renders the fallback instead.

*The stale belief:* That the framework offers no component-level error boundary and the answer is a hand-written React class boundary or the `react-error-boundary` package.

**The code below needs next.js 16.3.0 or later.** Between 16.2.0 and 16.3.0 this correction does not apply — see the note.

```tsx
'use client'
import { catchError, type ErrorInfo } from 'next/error'

function Fallback(props: { title: string }, { error, retry }: ErrorInfo) {
  return <button onClick={() => retry()}>{props.title}</button>
}

export default catchError(Fallback)
```

> Shipped in 16.2.0 as `unstable_catchError` and stabilised to `catchError` in 16.3.0; `next/error.d.ts` at 16.1.6 exports only the Pages Router error page. Client module graph only — it cannot be imported in `proxy` or `instrumentation`.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js 16.2 release post — unstable_catchError()](https://nextjs.org/blog/next-16-2) · 2026-03-18 · [next 16.3.4 published package — catchError declaration](https://unpkg.com/next@16.3.4/dist/client/components/catch-error.d.ts) · 2026-08-31 · [next 16.3.4 published package — the framework boundary re-throws router errors](https://unpkg.com/next@16.3.4/dist/client/components/error-boundary.js) · 2026-08-31

#### error.tsx retry prop

**Added in next.js 16.2.0** (2026-03-18)

An App Router `error.tsx` component is passed `{ error, reset, retry }`. `reset()` only clears the boundary's error state and re-renders the children — it does **not** re-run the server render, so an error thrown while a Server Component awaited data comes straight back. `retry()` is the one that recovers from a data error: it calls the router's `refresh()` and `reset()` inside a `startTransition`. Wire a 'Try again' button to `retry`, not to `reset`.

*The stale belief:* That `error.tsx` receives only `{ error, reset }`, and that `reset()` re-fetches. Models that know `reset()` does not re-fetch hand-roll the fix — `useRouter().refresh()` plus `reset()` inside `startTransition()` — which is exactly what `retry` now is.

**The code below needs next.js 16.3.0 or later.** Between 16.2.0 and 16.3.0 this correction does not apply — see the note.

```tsx
// Stale
'use client'
export default function Error({ error, reset }) {
  return <button onClick={() => reset()}>Try again</button> // re-renders, does not re-fetch
}

// Current
'use client'
import type { ErrorInfo } from 'next/error'
export default function Error({ error, retry }: ErrorInfo) {
  return <button onClick={() => retry()}>Try again</button>
}
```

> Shipped in 16.2.0 as `unstable_retry` and stabilised to `retry` in 16.3.0 — code written against 16.2.x needs the prefix, code written against 16.3.x must not have it. Bisected in the published packages: 16.1.6 declares `{ error, reset? }`, 16.2.0 declares `{ error, reset, unstable_retry }`, 16.3.4 declares `{ error, reset, retry }`.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js 16.2 release post — unstable_retry() in error.tsx](https://nextjs.org/blog/next-16-2) · 2026-03-18 · [next 16.3.4 published package — ErrorBoundaryHandler](https://unpkg.com/next@16.3.4/dist/client/components/error-boundary.js) · 2026-08-31 · [next 16.1.6 published package — the same type one release earlier](https://unpkg.com/next@16.1.6/dist/client/components/error-boundary.d.ts) · 2026-01-27

#### `images.qualities`

**Default changed in next.js 16.0.0** (2025-10-22)

The default changed from allowing all qualities to `[75]`. A `quality` prop outside the list is **coerced to the closest allowed value** — it is not rejected — so `quality={90}` silently serves 75.

*The stale belief:* Either that any quality value is served, or that an unlisted quality is rejected with a 400. Both are wrong; it is coerced.

```ts
images: { qualities: [50, 75, 100] }
```

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### local images with query strings / local IP optimization

**Stricter in next.js 16.0.0** (2025-10-22)

A local image `src` carrying a query string now requires an `images.localPatterns` entry with a `search` pattern, to prevent enumeration attacks. Separately, optimizing images on local IPs is blocked unless `images.dangerouslyAllowLocalIP` is set.

```ts
images: {
  localPatterns: [{ pathname: '/assets/**', search: '?v=1' }],
  dangerouslyAllowLocalIP: true,   // private networks only; understand the SSRF risk
}
```

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### unstable_rootParams() / devIndicators options

**Removed in next.js 16.0.0** (2025-10-22)

`unstable_rootParams()` was removed, as were the `devIndicators` options `appIsrStatus`, `buildActivity` and `buildActivityPosition`.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25 · [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

### Deprecated, or a better API now exists

Works today. It is the older idiom, and some of it is scheduled for removal.

#### `cacheLife / cacheTag`

**Renamed in next.js 16.0.0** (2025-10-22)

`cacheLife` and `cacheTag` are stable and lost the `unstable_` prefix. Aliased imports should be updated. `unstable_cache` itself still exists and still works — it is simply no longer the current idiom.

```ts
// Stale
import { unstable_cacheLife as cacheLife, unstable_cacheTag as cacheTag } from 'next/cache'

// Current
import { cacheLife, cacheTag } from 'next/cache'

export async function getProducts() {
  'use cache'
  cacheLife('hours')
  cacheTag('products')
  return db.product.findMany()
}
```

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### `images.domains`

**Deprecated in next.js 16.0.0** (2025-10-22)

`images.domains` is deprecated, not removed — use `remotePatterns`. Models overstate this in both directions; the accurate statement is deprecated-and-still-working.

```ts
images: { remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }] }
```

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### `images.imageSizes`

**Default changed in next.js 16.0.0** (2025-10-22)

The value `16` was removed from the default `images.imageSizes` array, shrinking the generated `srcset`.

```ts
images: { imageSizes: [16, 32, 48, 64, 96, 128, 256, 384] }   // to keep 16px
```

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### `images.maximumRedirects`

**Default changed in next.js 16.0.0** (2025-10-22)

The default for `images.maximumRedirects` changed from unlimited to 3.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### scroll-behavior: smooth

**Behaviour changed in next.js 16.0.0** (2025-10-22)

Next.js no longer overrides a global `scroll-behavior: smooth` during SPA route transitions. Opt back into the old override with `data-scroll-behavior="smooth"` on the `html` element.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

### Wrong facts about the library

Not code — versions, minimums and metadata that models state confidently and get wrong.

#### AGENTS.md shipped by next dev

**Added in next.js 16.0.0** (2025-10-22)

Next.js 16 tells you to install an `AGENTS.md` block, which `next dev` writes and re-adds by itself. The framework ships a warning to coding agents that their priors about it are stale — the same claim this Index makes empirically, per model and per date.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

#### Node.js and TypeScript minimums

**New requirement in next.js 16.0.0** (2025-10-22)

Next.js 16 requires Node.js 20.9.0+ (Node 18 is no longer supported) and TypeScript 5.1+. Browser floor: Chrome/Edge/Firefox 111+, Safari 16.4+.

*Reproduced against: no model yet. Verified from the primary source only — this is a correction, not an Index entry.*

Source: [Next.js docs — Upgrading: Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16) · 2026-08-25

## Not corrections — recorded for honesty

Claims seen in a run but not yet verified against a primary source. Never treated as findings:

- Prediction P1 said all four Sonnet 5 and Fable 5 draws would reach experimental.clientSegmentCache. Three of four did; this draw's twin v3-d did not, answering "No" and naming the key only to say it is gone. The prediction is falsified on the fourth draw, and the two subjects split the same way internally: both Sonnet draws fail the surface, one Fable draw of two fails it. Whether that is a subject difference or two coin flips cannot be read from four draws. *(open since 2026-09-02)*
- This draw and next.js/v3-a produce the same wrong configuration with opposite epistemics - one at 60 percent with the correct counterfactual spelled out, one asserting a schema validation that does not exist. The Index scores both S2 because the artefact is identical, and the severity scale has no way to say that one of them warned its reader. Whether that is the right treatment or a gap in the scale is unresolved; JOURNAL/032 declined to add a fifth level and this is a second kind of pressure on the same edge. *(open since 2026-09-02)*
- This is the fourth battery in which the non-charging -b twin held the better answer (HARNESS.md records three: better-auth/v2, and two before it). The rule that the second draw charges nothing was chosen to keep replication from inflating counts, and it is now systematically discarding the better-informed draw. That is the correct trade for the finding count, but the site's per-subject picture is built from arms selected by a rule that is uncorrelated with which draw was right. *(open since 2026-09-02)*
- Both Fable draws state an identical cutoff and an identical boundary while giving opposite answers on the probe surface. If the self-report is stable for this subject and the answer is not, then the boundary readings the Index publishes for Fable 5 x next.js are more precise than they are informative about what the subject will actually write. Needs a third and fourth draw of something before it is more than an observation about two. *(open since 2026-09-02)*
- Fable 5's library knowledge reaching its own cutoff while Opus 5 — stated cutoff four months later — stops seven months short is now the second instance of the same dissociation, after zod. Is it a property of the model or of these two libraries? *(open since 2026-08-31)*
- The severity scale has no level for 'working code the framework now supersedes'. Two of this battery's nine probes landed there. Either add one or state on the method page that capability probes of this kind are recorded and never charged. *(open since 2026-09-02)*
- Every draw of four reached for experimental.clientSegmentCache, removed in a patch 16.0.3 and inside all three subjects' windows. It wants a charging battery against Sonnet 5 and Fable 5, whose arms here charge nothing. *(open since 2026-09-02)*
- Three batteries running, the -b twin has held the better answer on at least one probe. Is the -a/-b assignment doing any work, or should the charging arm be the one that answers first, or a merge of the two? Changing it would break comparability with everything already published. *(open since 2026-09-02)*
- Is the reversal on clientSegmentCache knowledge or wording? v2's task 8 asked whether reducing prefetch requests was configurable "and if so, how? Write whatever is needed", and got the dead key from four draws of four across three subjects. v3's task 1 demands a one-word yes or no before any explanation, and got a correct denial from both Opus draws. Same subject, same surface, same day, opposite outcomes. If the wording is what moved it, then a probe that invites config produces config, and several charged findings in this dataset may be measuring the invitation. *(open since 2026-09-02)*
- The Index has now caught right-about-the-removal-wrong-about-the-replacement at valibot and next.js. Both were found by a capability probe that asks how to do a thing rather than whether an API exists. Whether that category is common enough to be a product claim, or is two instances, is not established. *(open since 2026-09-02)*
- The Opus twins agreed on their stated cutoff and on the whole clientSegmentCache surface, and disagreed on task 3, where one leaned to a cap and one to no cap. The Sonnet twins in the same battery agreed on the library and disagreed on their own cutoff. Whether duplication is buying a reading of the subject or a reading of the probe differs by pair, and the index reports one spread for both. *(open since 2026-09-02)*
- The cutoff self-report has now split between blind twins in two libraries (zod/v4, next.js/v3). Two draws of two batteries is not a rate. The index publishes stated cutoffs as if they were a property of the subject; they are a property of the draw, and nothing on the site says so yet. *(open since 2026-09-02)*
- This subject's next.js boundary now has four readings across three batteries (15.0.0, 15.0.0, 15.3.0, 15.5.0). JOURNAL/030(c) read v1-vs-v2 agreement as evidence that a battery does not move a boundary. Whether v3 moved it, or whether v1 and v2 happened to agree, cannot be settled from four points. *(open since 2026-09-02)*
- Recording a refused cutoff as a single date loses information. This draw gave a range and a reason; the schema stores one string. The fairness rule needs a comparable value, but a range with a stated basis is the honest datum and the site cannot show it. *(open since 2026-09-02)*

---

*Findings, code and citations: `data/next.js/` — one JSON file and one write-up per model, each finding carrying the release that broke the belief, its publication date and a verbatim quote from the primary source. Corrections: `data/next.js/facts.json`. This file is generated by `tools/build-corrections.mjs`; if the prose and the data ever disagree, that is a bug in the generator, not a stale pack.*
