From ce7570e898acd984e0aa812a68cc1cc602721069 Mon Sep 17 00:00:00 2001 From: Ben Senescu <44480372+bensenescu@users.noreply.github.com> Date: Wed, 26 Aug 2026 09:40:47 -0400 Subject: [PATCH] Stop reporting GA4 quota exhaustion as an app exception (#527) --- src/serverFunctions/ga4.ts | 10 ++++++++++ src/shared/error-codes.test.ts | 1 + src/shared/error-codes.ts | 3 +++ 3 files changed, 14 insertions(+) diff --git a/src/serverFunctions/ga4.ts b/src/serverFunctions/ga4.ts index 03532bf..a26277e 100644 --- a/src/serverFunctions/ga4.ts +++ b/src/serverFunctions/ga4.ts @@ -5,6 +5,7 @@ import { z } from "zod"; import { shiftGa4Date } from "@/server/features/ga4/services/Ga4Dates"; import { Ga4OrganicOverviewService } from "@/server/features/ga4/services/Ga4OrganicOverviewService"; import { Ga4Service } from "@/server/features/ga4/services/Ga4Service"; +import { AppError } from "@/server/lib/errors"; import { Ga4ReportError } from "@/server/lib/ga4Errors"; import { hasSelfHostedGoogleOAuthConfig } from "@/server/features/google/oauth-config"; import { @@ -123,6 +124,15 @@ export const getGa4DashboardReport = createServerFn({ method: "POST" }) ) { return { connected: false as const }; } + // Google's per-property reporting quota is exhausted: an external, + // transient condition, not an app fault. Surface it as RATE_LIMITED so + // error tracking skips it — the card keeps its own "try again" copy. + if ( + error instanceof Ga4ReportError && + error.code === "ga4_quota_exhausted" + ) { + throw new AppError("RATE_LIMITED"); + } throw error; } }); diff --git a/src/shared/error-codes.test.ts b/src/shared/error-codes.test.ts index 088b577..ee5b850 100644 --- a/src/shared/error-codes.test.ts +++ b/src/shared/error-codes.test.ts @@ -10,6 +10,7 @@ describe("shouldCaptureAppErrorCode", () => { "AUDIT_CAPACITY_REACHED", "AUDIT_PAGE_LIMIT_EXCEEDED", "AUDIT_ALREADY_RUNNING", + "RATE_LIMITED", ] as const)("skips expected %s errors", (code) => { expect(shouldCaptureAppErrorCode(code)).toBe(false); }); diff --git a/src/shared/error-codes.ts b/src/shared/error-codes.ts index be07481..c4c34bb 100644 --- a/src/shared/error-codes.ts +++ b/src/shared/error-codes.ts @@ -27,6 +27,9 @@ export type ErrorCode = z.infer; const NON_REPORTABLE_ERROR_CODES = new Set([ "UNAUTHENTICATED", + // External throttling (Google Analytics quota, Autumn, DataForSEO): expected + // and transient, and nothing in the app can act on it. + "RATE_LIMITED", "NOT_FOUND", "PAYMENT_REQUIRED", "INSUFFICIENT_CREDITS",