next.js
fa56f2c1 - fix: revalidateTag with profile should not trigger client cache invalidation (#88069)

Commit
9 days ago
fix: revalidateTag with profile should not trigger client cache invalidation (#88069) ## Summary Fixes a bug where calling `revalidateTag(tag, profile)` incorrectly triggers client-side cache invalidation, causing read-your-own-writes behavior that violates stale-while-revalidate semantics. ### The Problem When `revalidateTag('tag', 'max')` is called in a server action: 1. The tag is correctly marked for stale-while-revalidate 2. BUT the `x-action-revalidated` header is incorrectly set to `1` 3. This triggers client-side cache invalidation via `revalidateEntireCache()` 4. The client navigates and may display stale data from background revalidation This caused the confusing behavior where: - Click 1: Nothing happens (correct) - Click 2: Nothing happens (correct) - Click 3: Data changes to a stale value from click 1 (incorrect!) ### The Fix In `addRevalidationHeader`, change the `isTagRevalidated` calculation to only count tags **without** a profile (from `updateTag`). Tags with a profile (from `revalidateTag`) should follow stale-while-revalidate semantics and not trigger immediate client-side cache invalidation. ```typescript // Before: const isTagRevalidated = workStore.pendingRevalidatedTags?.length ? 1 : 0 // After: const isTagRevalidated = workStore.pendingRevalidatedTags?.some( (item) => item.profile === undefined ) ? 1 : 0 ``` ### Expected Behavior After Fix | API | Profile | Header Set | Client Behavior | |-----|---------|------------|-----------------| | `updateTag(tag)` | `undefined` | ✅ Yes | Immediate refresh (read-your-own-writes) | | `revalidateTag(tag, 'max')` | `'max'` | ❌ No | Keep stale data (SWR) | | `revalidateTag(tag, { expire: 0 })` | `{ expire: 0 }` | ✅ Yes* | Immediate refresh | *For immediate expiration via `pathWasRevalidated` which is already handled correctly. ## Test Plan - [x] Added new test page at `test/e2e/app-dir/use-cache/app/(partially-static)/revalidate-tag-no-refresh/page.tsx` - [x] Added test case that verifies 3 clicks of `revalidateTag` with profile don't change the displayed value - [x] Verified existing `updateTag` test (`should update after revalidateTag correctly`) still passes - [x] Verified both tests pass with `pnpm test-start` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Author
Parents
Loading