Bug: Success-path res.json() calls in monitor mutation hooks lack .catch() fallback
Severity: low
Location: client/src/hooks/use-monitors.ts:107, client/src/hooks/use-monitors.ts:197, client/src/hooks/use-monitors.ts:241
Background / Context
The mutation hooks useUpdateMonitor, useCheckMonitorSilent, and useUpdateMonitorSilent in client/src/hooks/use-monitors.ts call await res.json() on their success paths (after confirming res.ok is true) without a .catch(() => ({})) fallback. This is the same class of issue as #308 and #310 (which cover error paths), but affects the success path instead. If an intermediary proxy or CDN returns a 200 response with a non-JSON body (e.g., an HTML page from a misconfigured load balancer), the res.json() call throws a SyntaxError. React Query catches the thrown error, so the app does not crash, but the user sees an unhelpful SyntaxError message instead of a meaningful response.
How to Reproduce
- Log in to FetchTheChange and navigate to a monitor detail page.
- Trigger a condition where a reverse proxy or CDN returns a 200 status with an HTML body instead of JSON for
PATCH /api/monitors/:id or POST /api/monitors/:id/check. This can happen when:
- A transparent caching proxy serves a stale HTML response.
- A CDN or WAF inserts a challenge page but returns 200 instead of a proper error status.
- Edit and save a monitor (triggers
useUpdateMonitor), or use the Fix Selector flow (triggers useCheckMonitorSilent and useUpdateMonitorSilent).
Actual Result
The mutation enters React Query's error state with a SyntaxError message like "Unexpected token '<', '<!DOCTYPE '... is not valid JSON". For useUpdateMonitor, the toast shows this unhelpful error. For useCheckMonitorSilent and useUpdateMonitorSilent, there is no onError handler, so the error is silently swallowed by React Query -- the UI gives no feedback at all about the failure.
Expected Result
The success-path res.json() calls should include a .catch() fallback or a pre-check of the Content-Type header, so that non-JSON 200 responses produce a clear, actionable error message (e.g., "Unexpected response format from server") rather than a raw SyntaxError.
Affected hooks
useUpdateMonitor() — line 107
useCheckMonitorSilent() — line 197
useUpdateMonitorSilent() — line 241
Found by
Magicwand Phase 6 (Bug Reporter) on branch claude/fix-github-issues-C9ztu
Bug: Success-path res.json() calls in monitor mutation hooks lack .catch() fallback
Severity: low
Location:
client/src/hooks/use-monitors.ts:107,client/src/hooks/use-monitors.ts:197,client/src/hooks/use-monitors.ts:241Background / Context
The mutation hooks
useUpdateMonitor,useCheckMonitorSilent, anduseUpdateMonitorSilentinclient/src/hooks/use-monitors.tscallawait res.json()on their success paths (after confirmingres.okis true) without a.catch(() => ({}))fallback. This is the same class of issue as #308 and #310 (which cover error paths), but affects the success path instead. If an intermediary proxy or CDN returns a 200 response with a non-JSON body (e.g., an HTML page from a misconfigured load balancer), theres.json()call throws aSyntaxError. React Query catches the thrown error, so the app does not crash, but the user sees an unhelpful SyntaxError message instead of a meaningful response.How to Reproduce
PATCH /api/monitors/:idorPOST /api/monitors/:id/check. This can happen when:useUpdateMonitor), or use the Fix Selector flow (triggersuseCheckMonitorSilentanduseUpdateMonitorSilent).Actual Result
The mutation enters React Query's error state with a
SyntaxErrormessage like "Unexpected token '<', '<!DOCTYPE '... is not valid JSON". ForuseUpdateMonitor, the toast shows this unhelpful error. ForuseCheckMonitorSilentanduseUpdateMonitorSilent, there is noonErrorhandler, so the error is silently swallowed by React Query -- the UI gives no feedback at all about the failure.Expected Result
The success-path
res.json()calls should include a.catch()fallback or a pre-check of theContent-Typeheader, so that non-JSON 200 responses produce a clear, actionable error message (e.g., "Unexpected response format from server") rather than a raw SyntaxError.Affected hooks
useUpdateMonitor()— line 107useCheckMonitorSilent()— line 197useUpdateMonitorSilent()— line 241Found by
Magicwand Phase 6 (Bug Reporter) on branch
claude/fix-github-issues-C9ztu