APP_ROUTE entries are cached with empty tags, so revalidateTag/revalidatePath never invalidates route handlers
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- next.js, redis, typescript
Research direction
Start in packages/nextjs-cache-handler/src/handlers/cache-handler.ts around lines 788-803 and trace set() alongside getTagsFromHeaders(). Reproduce with an APP_ROUTE such as app/sitemap.xml/route.ts, then verify that revalidatePath('/sitemap.xml') invalidates the cached entry and its persisted tags are no longer empty.
Written by the indexing model from the issue text.
Description
APP_ROUTE entries are stored with tags: [], so revalidateTag — and therefore revalidatePath — never matches them. Route handlers stay cached until they expire on their own.
Sibling of #224 (same kind, different helper), and the same class of bug that #227 fixed for PAGES.
Cause
In set(), tags are taken from ctx.tags and only re-derived for two kinds:
switch (value?.kind) {
case "APP_PAGE": {
cacheHandlerValueTags = getTagsFromHeaders(value.headers ?? {});
break;
}
case "PAGES": {
const pathTag = getImplicitPathTag(cacheKey);
...
}
default: { // ← APP_ROUTE lands here
break;
}
}
APP_ROUTE falls to default, keeping ctx.tags — and Next does not populate ctx.tags for route handlers. It does send the tags, in the x-next-cache-tags response header that getTagsFromHeaders() already reads for APP_PAGE.
Measured on Next 15.5.22, logging the arguments set() receives:
APP_ROUTE /sitemaps/products.xml
ctx keys ["cacheControl", "isRoutePPREnabled", "isFallback"]
ctx.tags (absent)
ctx.cacheControl { revalidate: 3600 }
headers['x-next-cache-tags'] _N_T_/layout,
_N_T_/sitemaps/layout,
_N_T_/sitemaps/products.xml/layout,
_N_T_/sitemaps/products.xml/route,
_N_T_/sitemaps/products.xml
So the implicit path tag _N_T_/sitemaps/products.xml is available and simply not persisted. Since revalidatePath('/x') works by revalidating _N_T_/x, nothing can invalidate the entry.
Reproduction
- A route handler with
export const revalidate = 3600— e.g.app/sitemap.xml/route.ts. - Request it once so it caches.
revalidatePath('/sitemap.xml').- Request again.
Stored entry, before and after:
{
"lastModified": 1785665885071, // unchanged after revalidatePath
"lifespan": { "staleAge": 31536000, ... },
"tags": [], // ← empty
"value": {
"kind": "APP_ROUTE",
"headers": { "x-next-cache-tags": "_N_T_/layout,…,_N_T_/sitemap.xml" }
}
}
lastModified never advances. The same test against an APP_PAGE passes, which is what makes this easy to miss — a page-only test of revalidation looks completely healthy while every route handler is frozen.
Impact
Worse in combination with #224. Because resolveRevalidateValue() also skips APP_ROUTE, these entries get the default staleAge (~1 year) and cannot be revalidated on demand — so a route handler is effectively cached forever.
For us that was the XML sitemaps: they would have sat frozen in Redis while the content pipeline's revalidatePath calls silently did nothing. robots.txt and OG image routes have the same shape.
Suggested fix
APP_ROUTE carries the same header APP_PAGE does, so the existing helper covers it:
case "APP_PAGE":
case "APP_ROUTE": {
cacheHandlerValueTags = getTagsFromHeaders(value.headers ?? {});
break;
}
Happy to open a PR for this and for #224 if that helps.
Versions
@fortedigital/nextjs-cache-handler2.5.3, and confirmed still present in 3.2.1 and onmainnext15.5.22, App Router,output: standalone, self-hostedredis5.12.1 with theredis-stringshandler
- Dominant language
- TypeScript
- Stars
- 189
- Forks
- 29
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from fortedigital/nextjs-cache-handler
-
Difficulty 4/5 3-5 days Newbie friendliness 38/100
fortedigital/nextjs-cache-handler#212 · 3 comments ·
-
3.0.0 candidate | Next 16 enhancement help wanted
Difficulty 4/5 3-5 days Newbie friendliness 48/100
fortedigital/nextjs-cache-handler#152 · 13 comments ·
-
enhancement help wanted
Difficulty 4/5 3-5 days Newbie friendliness 25/100
fortedigital/nextjs-cache-handler#51 · 6 comments ·
-
documentation
fortedigital/nextjs-cache-handler#37 · 10 comments · 1 reaction · 1 assignee ·
-
documentation enhancement on hold
fortedigital/nextjs-cache-handler#28 · 2 comments · 1 reaction · 1 assignee ·
All issues in fortedigital/nextjs-cache-handler
Similar issues
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 95/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Automattic/studio#4908 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100