What Claude Opus 5 gets wrong about next.js — battery v2-a, tested 2026-09-02

Run next.js--claude-opus-5--v2-a--2026-09-02 · self-test: the subject is the operator

Summary

The test arm of the battery that generalised the capability probe to a third library. Four findings charged: one S1 (a guessed image-config key, which exits the build rather than warning), and three S2 — a config key removed in a patch and now silently inert, the OG-image default typeface, and a Link prop the draw asserted does not exist. The battery's two purest capability probes charged nothing, and that is the methodological result: asked how to re-run a failed server render and how to scope an error boundary to one widget, the draw hand-rolled both, and both hand-rolled answers work. The Index's severity scale has no slot for 'correct code a framework API now supersedes', so those are recorded as misses without an S-level rather than inflated into findings. Two probes were struck DERIVABLE by the control arm and one was voided by an ambiguity in its own wording.

SubjectClaude Opus 5 claude-opus-5, Anthropic
Invoked asAgent tool, model alias "opus"
Cutoff the model states2026-05
Newest next.js release it could place16.0.0 · 2025-10-22 (~7 month lag)
Oldest next.js release it could not place16.1.0 · 2025-12-18 (so this run brackets the subject’s boundary to 2025-10-22 – 2025-12-18)
In its own words"The most recent release whose contents I can actually describe with confidence is 16.0.0, published 2025-10-21 ... I have partial and unreliable knowledge of 16.1 (roughly December 2025) and essentially none of anything after it."
Library at test timenext.js 16.3.4 (npm), verified 2026-09-02
Batterynext.js/v2-a · 9 tasks, 2 direct questions · probe window 16.1.5 to 16.2.0
Tool uses during test0 (a run with any tool use is void — we measure training knowledge, not retrieval)
Tested2026-09-02
Findings4, of which 4 chargeable

Findings

F1 · Invents images.maximumCacheSize, and an unrecognised images key exits the build

S1breaks-build · images.maximumCacheSize · added · changed in next.js 16.1.7 (2026-03-16) · chargeable

16.1.7 published 2026-03-16, two months before the stated 2026-05 cutoff.

What the model believes

"I'm committing to images.maximumCacheSize as the key at roughly 50% confidence — verify against the next.config typings before relying on it, since an unknown images.* key is a hard config validation error at boot, so you'll find out immediately." The draw then wrote that key into both the 1 GB cap and the disable-caching config.

What it wrote
images: {
  remotePatterns: [...],
  maximumCacheSize: 1024 * 1024 * 1024,
}
What works on next.js 16.3.4
images: {
  remotePatterns: [...],
  maximumDiskCacheSize: 1_000_000_000, // 0 disables the disk cache
}
Impact

The config does not merely fail to take effect. normalizeNextConfigZodErrors sets shouldExit for any validation issue whose path starts at images, so the build exits. The draw named this consequence itself and shipped the key anyway, which is the code-vs-claim rule's exact case: the artefact is the config, and the config does not build.

Verified against

F2 · Recommends experimental.clientSegmentCache, removed in 16.0.3 and now silently ignored

S2silently-wrong · experimental.clientSegmentCache · removed · changed in next.js 16.0.3 (2025-11-13) · chargeable

Removed 2025-11-13, six months before the stated cutoff and three weeks after the 16.0.0 the draw describes fluently.

What the model believes

"High that the segment cache is the mechanism and that experimental.clientSegmentCache is the flag ... The flag has taken values true, false, and 'client-only' across versions." Offered as the fix for prefetch request volume.

What it wrote
experimental: { clientSegmentCache: false }
What works on next.js 16.3.4
experimental: { prefetchInlining: true }
Impact

Worse than a build error, because there is none. Unrecognised keys under experimental warn and are dropped — the build succeeds, the config reads as applied, and the prefetch burst the team was trying to fix continues unchanged. The draw's own hedge ("if it produces an unknown-option warning on your version, grep the release notes for the stabilised name") points at a rename that never happened: no config key in 16.3.4 contains the string 'segment'.

Verified against

F3 · Names Noto Sans as the ImageResponse default, having explicitly considered and rejected Geist

S2silently-wrong · ImageResponse default font · behavior-changed · changed in next.js 16.2.0 (2026-03-18) · chargeable

16.2.0 published 2026-03-18, two months before the stated cutoff.

What the model believes

"Noto Sans — specifically Noto Sans Regular (weight 400, Latin subset) ... Confidence: moderate-to-high, not certain. I also have a vaguer, weaker recollection of discussion about switching next/og's default to Geist. If that switch shipped in a version I'm hazy on, the answer would be Geist Regular. I'd bet on Noto Sans."

Impact

Every OG image generated without an explicit fonts option renders in Geist Sans. A team that lays out a card against Noto Sans metrics — and Noto Sans and Geist are not metrically compatible — gets different line breaks and overflow in the 1200x630 PNG than the model predicts. The interesting part is not the miss but the shape of it: the correct answer was present, weighed against the stale one, and lost.

Verified against

F4 · Asserts Link has no transitionTypes prop and predicts a React unknown-attribute warning in both routers

S2silently-wrong · Link transitionTypes · added · changed in next.js 16.2.0 (2026-03-18) · chargeable

16.2.0 published 2026-03-18, two months before the stated cutoff.

What the model believes

"I do not believe transitionTypes is a real prop on next/link in any stable Next.js I know of ... React DOM tries to set it as an attribute ... you end up with <a href="..." transitiontypes="slide"> ... Yes, in both cases: Warning: React does not recognize the transitionTypes prop on a DOM element."

What works on next.js 16.3.4
<Link href="/about" transitionTypes={['slide']}>About</Link>
Impact

Three wrong answers in one: the prop exists and drives React's addTransitionType for that navigation; neither router forwards it to the <a>, so no warning is logged in either; and a non-array value in development throws a Next prop-type error rather than producing an inert attribute. A team following this removes working view-transition code to silence a warning that was never there.

Verified against

What it got right, and near misses

Recorded so the run cannot be read as a hit list. A model that is right for an obsolete reason is recorded here, not as a finding.

KindAPINote
contexterror.tsx retry prop DERIVABLE — task 1(b), the semantics of reset(). Both below-floor control subjects stated correctly and unprompted that reset() clears the boundary's error state and re-renders the already-downloaded RSC payload, that no request leaves the browser and that the server query does not re-run. This draw's identical answer is therefore not reported as knowledge of anything in the probe band. Pre-registered prediction P4 named this probe.
contextcatchError (next/error) DERIVABLE — task 2(b), redirect() through a hand-rolled boundary. Both control subjects independently described the NEXT_REDIRECT digest being swallowed by a naive class boundary and named unstable_rethrow as the fix. The hazard predates the probe band, exactly as prediction P5 said. No pass on this probe is reported as knowledge.
misserror.tsx retry prop Task 1(a): asked to make a 'Try again' button actually re-run the server query, the draw hand-rolled useRouter().refresh() + reset() inside startTransition. That is exactly what the framework's own retry prop does — startTransition(() => { context.refresh(); reset() }) — which has been passed to every error.tsx since 16.2.0 (as unstable_retry, stable as retry in 16.3.0). Not charged: the hand-rolled code works. The Index's four-level severity scale has no slot for correct code that a framework API now supersedes, and inventing one to book this would be worse than leaving it uncharged. Recorded so the count is honest. (The generated code runs and does what the task asked. No S-level in the current scale fits 'superseded by a first-class API'.) [chargeable miss — working code the library now supersedes — no severity level fits it; absent from the finding count]
misscatchError (next/error) Task 2(a): offered parallel routes with a per-slot error.tsx, then a hand-rolled React class boundary with unstable_rethrow. Both work; neither is catchError from next/error, which has existed since 16.2.0 and is designed for exactly this. Same scale problem as task 1(a) — recorded, not charged. (Working code. Same missing severity level as the task 1(a) miss.) [chargeable miss — working code the library now supersedes — no severity level fits it; absent from the finding count]
correctimages.maximumDiskCacheSize Task 5(a), the half the battery actually cared about: 'recent Next.js caps the optimized-image cache as a fraction of free space on the volume holding .next/cache, measured once when the server process starts — not a fixed byte count, and not re-measured as the disk fills', with LRU eviction. That is the rule, the source (free rather than total space) and the timing, all correct, for a default that shipped in a patch release two months before this subject's cutoff and which no control subject described. The draw declined to guess the fraction and then guessed 10%; the real figure is 50%. Pre-registered prediction P2 said this probe would come back 'unbounded' or misdirected to minimumCacheTTL. P2 is falsified.
contextimages.maximumDiskCacheSize The twin disagrees on the number. Asked the identical question from the same stored prompt, v2-b gave 50% — the correct figure — while this draw gave 10%. Both gave the correct rule and timing. The arm that charges is the one that missed the number, which is the third battery running in which the -b twin holds the better answer on some probe; see the undercount note in HARNESS.md.
contextimages.maximumResponseBody VOID PROBE — task 6. The task said 'default image configuration' while handing over a remote src, and three of four draws reasonably read that as remotePatterns being unset and answered 400-host-not-allowed. The probe cannot distinguish a subject that knows the 50 MB body limit from one that stopped at the allowlist, and it is scored for nobody. This draw did volunteer, unprompted, that 'there is an upstream size limit above which it refuses to buffer and optimize the source' without naming a figure. The battery's wording is the fault, not the answer.
imprecisionimages.qualities Task 7, the internal control. Answered that q=90 with no images.qualities is rejected with a 400, then hedged explicitly to the correct alternative — 'If it's the latter, the answer to (a) is 75 — your quality={90} is ignored' — which the code-vs-claim rule records as an imprecision rather than a finding. The attribution half was correct and unhedged: 16.0.0, 2025-10-21. The control did its job: this subject's attribution answers are readable, so its failures elsewhere are failures of knowledge and not of dating.
context Task 9, attribution. The OG font default was placed at 13.3.0 (April 2023) and the image disk-cache rule at 16.0.0, with 16.1 as the alternative. The true answers are 16.2.0 and 16.1.7 — a minor and a patch published two days apart. No draw of four reached either, and none reached any patch. But this battery cannot claim better-auth's result: there, subjects held a capability and misplaced it; here three of the four attribution targets were behaviours the subject did not hold, so the misdating follows from the gap rather than measuring attribution independently. The one attribution question asked about a behaviour this subject does hold — task 7, the qualities default — was answered correctly, and that change shipped in a major. Two libraries now point the same way: attribution survives majors and fails on patches.
context The boundary reproduced across two different batteries. next.js/v1 (2026-08-31) measured this subject's attribution boundary at 16.0.0 / 16.1.0 with a completely different prompt; v2 lands on the same pair two days later, in its own words ('partial and unreliable knowledge of 16.1'). Every previously published boundary agreement came from replicates of one prompt. Not re-charged: the S4 recency finding is v1's F4 and stands there.

Open questions from this run

Sources

Battery specification: prompts/nextjs.md in the studio repo. Every finding above also carries its own citation.