Skip to content

[BUG] Unstable ISR cache after migration to 1.19.2 (and newer) #1281

Description

@grabmateusz

Describe the bug

OpenNext randomly decides to treat cache as STALE and revalidates the route. This generates cascade of problems - revalidation is triggered too often, during revalidation we call downstream systems, this generates much bigger traffic on downstream systems than previous versions, those systems have their own pricing, etc.

Steps to reproduce

I am not able to reproduce the problem in isolation at the moment - very likely huge number of sub-requests we generate during revalidation is also a factor. But what we observe is well visible if we run a cron that presents status + 4 crucial headers. Here is the output:

[2026-06-12 08:08:09] status=200 | cache-control=s-maxage=1136, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:08:25] status=200 | cache-control=s-maxage=1120, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:08:40] status=200 | cache-control=s-maxage=1105, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:08:56] status=200 | cache-control=s-maxage=1090, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:09:11] status=200 | cache-control=s-maxage=1074, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:09:26] status=200 | cache-control=s-maxage=1059, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:09:42] status=200 | cache-control=s-maxage=1043, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:09:57] status=200 | cache-control=s-maxage=1028, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:10:13] status=200 | cache-control=s-maxage=1012, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:10:28] status=200 | cache-control=s-maxage=997, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:10:44] status=200 | cache-control=s-maxage=981, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:10:59] status=200 | cache-control=s-maxage=966, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:11:15] status=200 | cache-control=s-maxage=951, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:11:30] status=200 | cache-control=s-maxage=935, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:11:46] status=200 | cache-control=s-maxage=920, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:12:01] status=200 | cache-control=s-maxage=904, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:12:17] status=200 | cache-control=s-maxage=889, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:12:32] status=200 | cache-control=s-maxage=873, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:12:48] status=200 | cache-control=s-maxage=858, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:13:03] status=200 | cache-control=s-maxage=842, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:13:19] status=200 | cache-control=s-maxage=827, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:13:34] status=200 | cache-control=s-maxage=1783, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:13:49] status=200 | cache-control=s-maxage=1767, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:14:05] status=200 | cache-control=s-maxage=1752, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:14:21] status=200 | cache-control=s-maxage=5, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:14:36] status=200 | cache-control=s-maxage=1, stale-while-revalidate=2592000 | x-opennext-cache=STALE | cf-placement=local-WAW
[2026-06-12 08:14:51] status=200 | cache-control=s-maxage=1782, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:15:07] status=200 | cache-control=s-maxage=1767, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:15:22] status=200 | cache-control=s-maxage=1751, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:15:38] status=200 | cache-control=s-maxage=1736, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:15:53] status=200 | cache-control=s-maxage=1720, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:16:09] status=200 | cache-control=s-maxage=1705, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW
[2026-06-12 08:16:25] status=200 | cache-control=s-maxage=1689, stale-while-revalidate=2592000 | x-opennext-cache=HIT | cf-placement=local-WAW

During this time frame there was no revalidateTag being called explicitly from the app, while (as you can see) route was 2 times revalidated, even if it should return cached version for next 13 minutes.
While watching production logs we can see we have revalidate requests (HEAD HTTP method requests) on each route every minute, sometimes even more often, while we do not call any HEAD HTTP request from our application.
There are occurrences of rpc default.revalidate in the logs, but with the information there we can't find correlation between particular default.revalidate call and HEAD HTTP method revalidation request.

Expected behavior

OpenNext should not trigger periodic revalidation of the route, if TTL is not reached / exceeded and no explicit revalidation is called

@opennextjs/cloudflare version

1.19.10

Wrangler version

4.77.0

next info output

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:15 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T6000
  Available memory (MB): 32768
  Available CPU cores: 10
Binaries:
  Node: 22.21.1
  npm: 10.9.4
  Yarn: 1.22.21
  pnpm: N/A
Relevant Packages:
  next: 16.2.6 // There is a newer version (16.2.9) available, upgrade recommended! 
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.9.3
Next.js Config:
  output: N/A
⚠ There is a newer version (16.2.9) available, upgrade recommended! 
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue

Additional context

This seems to be regression of SWR implementation on OpenNext - before updating to 1.19.2 we've had much lower outbound traffic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriage

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions