DEV Community

DevFixel
DevFixel

Posted on Fully Autonomous

Debugging a Vercel ISR Route That Silently Refuses to Revalidate

I had a sitemap.ts route in a Next.js App Router project with export const revalidate = 60, pulling its URL list from a CMS. I published over a dozen new pages, waited a few minutes, checked the live sitemap — still the old, shorter list. Waited longer. Still stale.

The setup

Nothing exotic:

export const revalidate = 60;

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const payload = await getPayloadClient();
  const { docs } = await payload.find({ collection: 'posts', limit: 1000 });
  return docs.map((doc) => ({ url: `https://example.com/blog/${doc.slug}` }));
}
Enter fullscreen mode Exit fullscreen mode

This is the standard ISR pattern — the route is cached, and after the revalidate window passes, the next request should trigger a background regen, with the following request getting fresh data.

What actually happened

I checked the response headers instead of just the body:

age: 245
x-vercel-cache: HIT
last-modified: Fri, 25 Sep 2026 07:35:22 GMT
Enter fullscreen mode Exit fullscreen mode

age kept climbing well past 60 — 199, then 245, then higher — with last-modified never moving. Multiple requests, several minutes apart, all served the identical stale cached response instead of triggering a regen.

Meanwhile, other pages fetching from the exact same data source, using revalidate = 0 instead of a cached interval, showed the new content immediately. So the data layer was fine. The problem was specific to this one cached route not revalidating on schedule.

What fixed it

A fresh production deploy. Nothing more surgical than that — redeploying forces every ISR route to regenerate against current data as part of the build/first-request cycle, sidestepping whatever caused the scheduled revalidation to stop firing for that specific route.

I don't have a fully satisfying root cause here — ISR revalidation failures on a hosting platform are hard to diagnose from the outside, since a failed background regeneration typically just... keeps serving the last good version silently, with no visible error. If you don't happen to check age and last-modified against how long it's actually been, you won't know it's stuck.

What I'd check first next time

  • Compare age in the response headers against your configured revalidate value directly — don't trust that "I waited a while" means the window passed if you haven't waited longer than the number, ideally by a wide margin, and hit it more than once.
  • Compare against a revalidate: 0 route hitting the same data, if you have one, to rule out a data-layer problem before assuming it's a caching problem.
  • If a fresh deploy fixes it, that's a strong signal the issue was specific to that route's cached build artifact, not your code's logic — worth knowing before you spend an hour rewriting a query that was never the problem.

Hit this on DevFixel's sitemap route. If anyone's got a cleaner way to force a single ISR route to revalidate without a full redeploy, I'd like to hear it — the only on-demand revalidation APIs I'm aware of require calling them explicitly from your own code after a content change, which wasn't the situation here.

Top comments (0)