Payload Plugins
Pluginspayload-revalidate

Troubleshooting

Fix the common revalidation failures fast — a symptom-first table with the literal dev warnings to grep for, plus the /dev/revalidate map that shows exactly what busts when.

For AI / LLMs: View Markdown

Revalidation is loud when it goes wrong. The plugin logs each failure once per process, in every environment — a production jobs runner silently not revalidating is the one thing it refuses to be quiet about. Every message is prefixed [payload-revalidate], so grep '\[payload-revalidate\]' on your logs surfaces all of them. The literal strings are in the table below.

SymptomCauseFix
Nothing revalidates in a jobs runner or outside a requestrevalidateTag no-ops outside a Next request scope (a console.warn, once). Grep: revalidateTag('…') was a no-op — no Next request scope.Bust from inside a request, or accept that background writes heal on the next request-scoped bust. This is the failure the plugin logs loudest.
Entry materialized untaggedcacheTag failed, so the entry carries no tags and nothing can bust it (a console.error, once). Grep: cacheTag failed — this entry (and likely every entry) is materializing UNTAGGED.Confirm the getter runs inside a 'use cache' scope with cacheComponents enabled.
Bake-in walk skippedThe config was unreachable, so the walk that finds baked-in content couldn't run (a console.warn).The doc still tags by id; only the deep-content walk was skipped. Check the logged warning for the cause.
Hooks don't fire on a plugin's collectionThe plugin ran before the collection existed, so it couldn't hook it. Grep: registered AFTER revalidatePlugin() and NOT hooked for revalidation.Register revalidatePlugin() last in plugins: []. The boot-time warning names anything registered after it. See Quickstart.
List reorders don't refreshThe read depends on a sort or filter field the scope doesn't declare, so a reorder never busts it.Declare every sort and filter field the scope depends on. The /dev/revalidate map warns when a scope is observed but undeclared. See Getters.
Nothing busts during a seedExpected — the payload-seed engine sets context.disableRevalidate on every write.Nothing to fix. The plugin's after-seed listener flushes the seeded surface once at the end: list tags, declared scopes, extraTags, and rule targets for the touched slugs, then all.

The three loud failures all log once per process in every environment, production included: revalidateTag no-oping outside a request scope (console.warn), cacheTag failing so an entry materializes untagged (console.error), and the config being unreachable so the bake-in walk is skipped (console.warn).

The /dev/revalidate map

With payload-dev-tools installed, the map renders in four tabs:

  • Explore — the interactive dependency graph (pan/zoom, click a node): editing a node makes its right-hand neighbors stale; amber animated edges are observed bake-ins (the anti-pattern), grey edges are id-references, dashed is richText. Selecting a node answers "what does editing this revalidate?" and "what makes this stale?" plus the observed doc-level reality: which entries carry media:3 right now, own-entry ✓ or baked-in ⚠.
  • Fields — per collection, every field with its computed blast radius: title → doc, publishedAt → doc + list:recent, slug → doc + alias.
  • Reads — every materialized entry with an atomic-health badge (atomic ✓, N baked-in ⚠, undeclared scope!, capped!).
  • Events — the bust log (per-tag reasons) + a manual bust box.

GET /api/revalidate-map serves it all as JSON (dev-gated); POST /api/revalidate-map { "tag": "posts:42" } busts one tag by hand.

The plugin also polices the pattern in dev: a getter baking in populated docs logs the exact field paths to fix; a cacheIds read carrying an undeclared scope warns that reorders won't reach it; docs-with-content passed to cacheIds warn that content edits won't refresh the entry.

Both routes are governed by observe, so they exist only while it is on — the production default registers neither. With observe: true forced on in production, they additionally require an authenticated Payload user.

Next

On this page