Skip to content

Commit 6c41d3e

Browse files
ralyodioclaude
andcommitted
fix(web): reject stale Server Action POSTs in middleware (real fix)
Replaces the console.error filter (which only hid the log noise) with middleware that short-circuits the requests causing the leak in the first place. Any POST carrying a Next-Action header against this bundle is by definition stale — no `use server` directives exist in the codebase, so the action ID can only have come from a previously deployed build cached on the client or replayed by bots. Returning 410 Gone before the request reaches Next's internal handler prevents the InvariantError path that was retaining per-request RSS under bot pressure (memory climbed 100MB → 1.35GB in ~13h on threatcrush.com on 2026-05-12 before this). Deletes apps/web/instrumentation.ts — it existed only to host the console.error suppression added in 14f9816, and Sentry instrumentation was already gone. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 14f9816 commit 6c41d3e

2 files changed

Lines changed: 19 additions & 18 deletions

File tree

apps/web/instrumentation.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

apps/web/src/middleware.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { NextResponse } from "next/server";
2+
import type { NextRequest } from "next/server";
3+
4+
// Any request carrying a Next-Action header is a Server Action invocation.
5+
// The current bundle defines no Server Actions, so every such request is a
6+
// stale-bundle hit (cached clients or bots replaying old action IDs). Letting
7+
// these reach Next's internal handler triggers an InvariantError on every hit
8+
// and leaks RSS under sustained load. Reject with 410 Gone before any of that
9+
// runs; the client framework treats a non-RSC response as a signal to reload.
10+
export function middleware(req: NextRequest): NextResponse | undefined {
11+
if (req.headers.get("next-action")) {
12+
return new NextResponse(null, { status: 410 });
13+
}
14+
return undefined;
15+
}
16+
17+
export const config = {
18+
matcher: "/((?!_next/static|_next/image|favicon.ico).*)",
19+
};

0 commit comments

Comments
 (0)