fix(trpc): suppress NOT_FOUND errors in onError handler#4534
Conversation
Old desktop clients (pre-1.5.0) still poll device.heartbeat which was removed in #4490. Those clients are gated behind UpdateRequiredPage and their calls have no downstream consumer, but the unconditional console.error was generating ~84k ERROR log entries since the route was deleted (2026-05-13). Suppress NOT_FOUND codes entirely — any removed or mistyped procedure hit by old clients should not pollute the error dashboard.
|
Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews. |
Greptile SummarySuppresses
Confidence Score: 4/5Safe to merge for the immediate log-spam problem; the only concern is that the early-return is not path-scoped, which could silently hide future NOT_FOUND errors from other removed procedures. The change correctly stops flooding the error dashboard from old clients polling a removed endpoint. The suppression is a blanket check on error.code rather than filtering by procedure path, so if a different procedure is removed in a future deploy and non-gated clients start hitting it, those errors would also vanish from logs without any signal. apps/api/src/app/api/trpc/[trpc]/route.ts — the onError guard warrants a second look for path-scoping.
|
| Filename | Overview |
|---|---|
| apps/api/src/app/api/trpc/[trpc]/route.ts | Adds a NOT_FOUND early-return in the tRPC onError handler to stop log spam from old desktop clients; suppression is global across all procedures rather than scoped to the removed path. |
Sequence Diagram
sequenceDiagram
participant OldClient as Old Desktop Client (< 1.5.0)
participant API as Next.js API Route
participant tRPC as tRPC fetchRequestHandler
participant onError as onError Handler
OldClient->>API: POST /api/trpc/device.heartbeat
API->>tRPC: route to appRouter
tRPC-->>onError: "error { code: NOT_FOUND, path: device.heartbeat }"
Note over onError: NEW: if error.code === NOT_FOUND return
onError-->>tRPC: suppressed, no console.error
tRPC-->>OldClient: 404 NOT_FOUND response
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
apps/api/src/app/api/trpc/[trpc]/route.ts:18
**Overly broad suppression of NOT_FOUND errors**
The guard silences every `NOT_FOUND` error across the entire tRPC surface, not just calls to `device.heartbeat`. If a currently-active procedure is removed or renamed in a future deploy and a web or mobile client (not gated by `UpdateRequiredPage`) starts hitting it, those errors will be silently swallowed here and produce no signal in logs or the error dashboard. Scoping the check to the known-dead path — e.g. `if (error.code === "NOT_FOUND" && path === "device.heartbeat") return;` — would contain the suppression to the intended case and preserve observability for any other `NOT_FOUND` that may arise.
Reviews (1): Last reviewed commit: "fix(trpc): suppress NOT_FOUND errors in ..." | Re-trigger Greptile
| // procedures (e.g. device.heartbeat removed in #4490). Those clients | ||
| // are gated behind UpdateRequiredPage and their calls have no | ||
| // downstream consumer — suppress to avoid false-positive error noise. | ||
| if (error.code === "NOT_FOUND") return; |
There was a problem hiding this comment.
Overly broad suppression of NOT_FOUND errors
The guard silences every NOT_FOUND error across the entire tRPC surface, not just calls to device.heartbeat. If a currently-active procedure is removed or renamed in a future deploy and a web or mobile client (not gated by UpdateRequiredPage) starts hitting it, those errors will be silently swallowed here and produce no signal in logs or the error dashboard. Scoping the check to the known-dead path — e.g. if (error.code === "NOT_FOUND" && path === "device.heartbeat") return; — would contain the suppression to the intended case and preserve observability for any other NOT_FOUND that may arise.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/api/src/app/api/trpc/[trpc]/route.ts
Line: 18
Comment:
**Overly broad suppression of NOT_FOUND errors**
The guard silences every `NOT_FOUND` error across the entire tRPC surface, not just calls to `device.heartbeat`. If a currently-active procedure is removed or renamed in a future deploy and a web or mobile client (not gated by `UpdateRequiredPage`) starts hitting it, those errors will be silently swallowed here and produce no signal in logs or the error dashboard. Scoping the check to the known-dead path — e.g. `if (error.code === "NOT_FOUND" && path === "device.heartbeat") return;` — would contain the suppression to the intended case and preserve observability for any other `NOT_FOUND` that may arise.
How can I resolve this? If you propose a fix, please make it concise.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Problem
After removing
device.heartbeatin #4490 (deployed ~2026-05-13 05:00 UTC), old desktop clients (pre-1.5.0) continued polling the now-deleted endpoint. TheonErrorhandler logged everyNOT_FOUNDhit atconsole.error, generating ~84,600 ERROR log entries over ~18 hours at ~1,100 errors / 15 min — polluting the error dashboard and burning Vercel log quota.Root Cause
The
onErrorcallback inapps/api/src/app/api/trpc/[trpc]/route.tslogs all tRPC errors unconditionally.NOT_FOUNDfrom old clients polling removed routes is expected, not actionable.Fix
Skip logging for
NOT_FOUNDerrors. These always come from old clients behind theUpdateRequiredPagegate — they can't use the app and their calls have no downstream consumer.Callers
All
device.heartbeatcallers confirmed to be desktop clients on versions 1.0.5–1.4.4, all below theMINIMUM_DESKTOP_VERSION = "1.5.0"floor.Summary by cubic
Suppress
NOT_FOUNDerrors for the removeddevice.heartbeattRPC procedure in the APIonErrorhandler. This hides expected hits from pre‑1.5.0 desktop clients and reduces noisy ERROR logs, while keeping otherNOT_FOUNDerrors visible.apps/api/src/app/api/trpc/[trpc]/route.ts, return early inonErroronly whenerror.code === "NOT_FOUND"andpath === "device.heartbeat".Written for commit 520d82d. Summary will update on new commits.