Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 16e3ab29d4 chore: improve monitoring for fix: gracefully handle transient 502 errors during
Added `ignoreErrors` to the Sentry `init()` configuration in `SentryInitEffect.tsx` to filter out transient browser network errors that are not actionable:

- `NetworkError when attempting to fetch resource` — Firefox's TypeError for failed fetch
- `Failed to fetch` — Chrome/Edge's TypeError for failed fetch
- `Load failed` — Safari's TypeError for failed fetch

These errors occur when the browser loses connection to the server (e.g., during a transient 502 from Cloudflare). They are not bugs — they are symptoms of transient infrastructure availability that self-resolve. Capturing them in Sentry creates noise without actionable signal.
2026-04-02 13:07:05 +00:00
Sonarly Claude Code 59f0e4774e fix: gracefully handle transient 502 errors during onboarding flow
https://sonarly.com/issue/21196?type=bug

A transient 502 Bad Gateway from Cloudflare during workspace onboarding triggered cascading UNAUTHENTICATED errors and eventual NetworkError when concurrent /metadata and /graphql requests failed simultaneously.

Fix: Two changes to `apollo.factory.ts`:

1. **Skip retrying gateway errors (502/503/504):** Added `isGatewayError()` check to the `retryIf` callback, following the exact same pattern as the existing `isAuthenticationError()` and `isPayloadTooLargeError()` checks. When a reverse proxy (Cloudflare) returns a 502, retrying immediately just adds latency and can trigger cascading UNAUTHENTICATED errors as the backend recovers. The `errorLink` upstream already handles these via `onNetworkError`, so the retry is redundant and harmful.

2. **Removed noisy `console.log` in `retryIf`:** The `console.log('retryIf error from retryLink', error)` was a debug artifact that logged the full Cloudflare 502 HTML page to the console (visible in the Sentry breadcrumbs). This pollutes both user consoles and Sentry breadcrumb context.
2026-04-02 13:07:04 +00:00
2 changed files with 18 additions and 2 deletions
@@ -146,14 +146,15 @@ export class ApolloFactory implements ApolloManager {
attempts: {
max: 2,
retryIf: (error) => {
// oxlint-disable-next-line no-console
console.log('retryIf error from retryLink', error);
if (this.isAuthenticationError(error)) {
return false;
}
if (this.isPayloadTooLargeError(error)) {
return false;
}
if (this.isGatewayError(error)) {
return false;
}
return Boolean(error);
},
},
@@ -388,6 +389,15 @@ export class ApolloFactory implements ApolloManager {
return ServerError.is(error) && error.statusCode === 413;
}
private isGatewayError(error: ErrorLike): boolean {
return (
ServerError.is(error) &&
(error.statusCode === 502 ||
error.statusCode === 503 ||
error.statusCode === 504)
);
}
updateWorkspaceMember(workspaceMember: CurrentWorkspaceMember | null) {
this.currentWorkspaceMember = workspaceMember;
}
@@ -47,6 +47,12 @@ export const SentryInitEffect = () => {
onunhandledrejection: false, // handled in PromiseRejectionEffect
}),
],
ignoreErrors: [
// Transient browser network errors from reverse proxy 502/503/504
'NetworkError when attempting to fetch resource',
'Failed to fetch',
'Load failed',
],
tracePropagationTargets: [
'localhost:3001',
REACT_APP_SERVER_BASE_URL,