diff --git a/.server-changes/attio-sync-transient-retry.md b/.server-changes/attio-sync-transient-retry.md new file mode 100644 index 0000000000..9c54416a46 --- /dev/null +++ b/.server-changes/attio-sync-transient-retry.md @@ -0,0 +1,6 @@ +--- +area: webapp +type: improvement +--- + +Transient internal sync failures are now retried quietly instead of surfacing as errors. diff --git a/apps/webapp/app/services/attio.server.ts b/apps/webapp/app/services/attio.server.ts index c26eca8e37..f0852509f4 100644 --- a/apps/webapp/app/services/attio.server.ts +++ b/apps/webapp/app/services/attio.server.ts @@ -47,13 +47,18 @@ class AttioClient { if (!response.ok) { const body = await response.text(); - logger.error("Attio assert failed", { - object, - matchingAttribute, - status: response.status, - body, - }); - throw new Error(`Attio assert ${object} failed with status ${response.status}`); + // 5xx/429 are transient (the worker retries); warn + tag so they don't page Sentry. Real 4xx stay error. + const transient = response.status >= 500 || response.status === 429; + const fields = { object, matchingAttribute, status: response.status, body }; + if (transient) { + logger.warn("Attio assert failed", fields); + } else { + logger.error("Attio assert failed", fields); + } + const message = `Attio assert ${object} failed with status ${response.status}`; + throw transient + ? Object.assign(new Error(message), { logLevel: "warn" as const }) + : new Error(message); } const recordId = ((await response.json()) as any).data?.id?.record_id;