Revalidate cache button calls a nonexistent route, always fails
Bug: "Revalidate cache" button calls a route that doesn't exist
File: components/links/links-table.tsx
Lines: 525–550 (handler), 1084 (button wiring)
Introduced in: 9b8f3c03 — "feat: add multiple brands" (2026-08-21)
What happens
The "Revalidate cache" action on a link row calls:
fetch(`/api/links/${link.id}/revalidate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ teamId: currentTeamId }),
})No route matches /api/links/[id]/revalidate anywhere in the codebase. The only revalidation endpoint that exists is pages/api/revalidate.ts, and it's a completely different shape:
- GET only — the handler returns 405 for anything else, including the POST this button sends
- Authenticated by a
secretquery param checked againstprocess.env.REVALIDATE_TOKENserver-side — not by session/team membership, so the frontend can't call it directly with the current request shape even after fixing the path and method - Takes
linkIdas a query parameter, not a URL path segment
So every click on "Revalidate cache" currently fails with the generic "Failed to revalidate link cache" toast, regardless of team or link.
Reproduction
- Open the links table for any document or dataroom
- Open the row menu for any link, click Revalidate cache
- Toast shows
Failed to revalidate link cacheevery time
Why this wasn't caught
response.ok is false for the 404 the router returns, so the failure path is exercised correctly — the toast fires as designed. The bug is upstream of that: the endpoint being called has never existed under this path, so there's no scenario in which this button succeeds.
Suggested fix
The real /api/revalidate.ts handler is secured by a server-only secret, which this button can't supply from the client. The likely correct fix is a new, session-authenticated route (e.g. POST /api/teams/[teamId]/links/[id]/revalidate) that checks team membership the way the rest of the team-scoped routes do, then internally triggers the same res.revalidate(...) calls that pages/api/revalidate.ts performs for a single link — rather than trying to reuse the existing secret-based endpoint from the client.
Happy to open a PR for this if that direction sounds right — wanted to confirm the intended auth model first, since I don't know if there's a reason the two revalidation paths were meant to stay separate.
Source: papermark/papermark