Skip to content

Commit 80cbc46

Browse files
fix(webapp): log transient Attio 5xx/429 at warn instead of error (#4270)
The signup → Attio sync (`attio.server.ts` `#assert`) logged every non-2xx response at `error` level and threw the same way regardless of status. Transient upstream failures (5xx/429) are retried by the common worker and self-heal, so treating them as errors created false alerts for something that isn't actually a bug. Now `#assert` splits the two cases: - **5xx / 429** — Logged at `warn` and thrown with `logLevel: "warn"`, so they continue to be retried but don't raise error-level alerts. This reuses the same pattern the worker already honors (`directorySyncEffects`). - **4xx** — Unchanged: logged at `error` and thrown, so genuine integration bugs (schema, permissions, auth, etc.) remain visible. There is no behavior change to retries or the signup flow. This is a server-only change. --------- Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 890dd66 commit 80cbc46

2 files changed

Lines changed: 18 additions & 7 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: improvement
4+
---
5+
6+
Transient internal sync failures are now retried quietly instead of surfacing as errors.

apps/webapp/app/services/attio.server.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,18 @@ class AttioClient {
4747

4848
if (!response.ok) {
4949
const body = await response.text();
50-
logger.error("Attio assert failed", {
51-
object,
52-
matchingAttribute,
53-
status: response.status,
54-
body,
55-
});
56-
throw new Error(`Attio assert ${object} failed with status ${response.status}`);
50+
// 5xx/429 are transient (the worker retries); warn + tag so they don't page Sentry. Real 4xx stay error.
51+
const transient = response.status >= 500 || response.status === 429;
52+
const fields = { object, matchingAttribute, status: response.status, body };
53+
if (transient) {
54+
logger.warn("Attio assert failed", fields);
55+
} else {
56+
logger.error("Attio assert failed", fields);
57+
}
58+
const message = `Attio assert ${object} failed with status ${response.status}`;
59+
throw transient
60+
? Object.assign(new Error(message), { logLevel: "warn" as const })
61+
: new Error(message);
5762
}
5863

5964
const recordId = ((await response.json()) as any).data?.id?.record_id;

0 commit comments

Comments
 (0)