Skip to content

fix(trpc): suppress NOT_FOUND errors in onError handler#4534

Merged
saddlepaddle merged 2 commits into
mainfrom
fix/trpc-not-found-error-log-noise
May 14, 2026
Merged

fix(trpc): suppress NOT_FOUND errors in onError handler#4534
saddlepaddle merged 2 commits into
mainfrom
fix/trpc-not-found-error-log-noise

Conversation

@sazabi
Copy link
Copy Markdown
Contributor

@sazabi sazabi Bot commented May 14, 2026

Problem

After removing device.heartbeat in #4490 (deployed ~2026-05-13 05:00 UTC), old desktop clients (pre-1.5.0) continued polling the now-deleted endpoint. The onError handler logged every NOT_FOUND hit at console.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 onError callback in apps/api/src/app/api/trpc/[trpc]/route.ts logs all tRPC errors unconditionally. NOT_FOUND from old clients polling removed routes is expected, not actionable.

Fix

Skip logging for NOT_FOUND errors. These always come from old clients behind the UpdateRequiredPage gate — they can't use the app and their calls have no downstream consumer.

Callers

All device.heartbeat callers confirmed to be desktop clients on versions 1.0.5–1.4.4, all below the MINIMUM_DESKTOP_VERSION = "1.5.0" floor.


Summary by cubic

Suppress NOT_FOUND errors for the removed device.heartbeat tRPC procedure in the API onError handler. This hides expected hits from pre‑1.5.0 desktop clients and reduces noisy ERROR logs, while keeping other NOT_FOUND errors visible.

  • Bug Fixes
    • In apps/api/src/app/api/trpc/[trpc]/route.ts, return early in onError only when error.code === "NOT_FOUND" and path === "device.heartbeat".

Written for commit 520d82d. Summary will update on new commits.

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-ai
Copy link
Copy Markdown

capy-ai Bot commented May 14, 2026

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-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 14, 2026

Greptile Summary

Suppresses NOT_FOUND tRPC errors in the onError handler to stop log flooding caused by old desktop clients (pre-1.5.0) polling the removed device.heartbeat procedure. The fix is a one-liner early return when error.code === \"NOT_FOUND\".

  • The suppression applies to all NOT_FOUND errors across every tRPC procedure, not just calls to the removed device.heartbeat path; a more targeted check on path would scope it to the intended case.
  • The PR rationale is sound for the immediate problem, and the impacted clients are confirmed to be gated behind UpdateRequiredPage.

Confidence Score: 4/5

Safe 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.

Important Files Changed

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
Loading
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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 14, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@saddlepaddle saddlepaddle merged commit 89da91a into main May 14, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant