Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions lib/media-location.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { requestAPI } from "@/lib/request";
import { requestAPI, ServerError } from "@/lib/request";
import * as Sentry from "@sentry/react-native";
import { Platform } from "react-native";

Expand Down Expand Up @@ -41,9 +41,11 @@ export const updateMediaLocation = async ({
} catch (error) {
// Log but don't throw - media location sync is non-critical
console.warn("Failed to update media location:", error);
// AbortError is expected when requests timeout (e.g. poor connectivity)
// during periodic background sync - no need to report to Sentry
if (!(error instanceof Error && error.name === "AbortError")) {
// AbortError (request timeout on poor connectivity) and ServerError (transient
// backend 5xx such as Heroku 502s) are expected during periodic background sync
// and are not actionable code bugs - no need to report to Sentry
const isAbortError = error instanceof Error && error.name === "AbortError";
if (!isAbortError && !(error instanceof ServerError)) {
Sentry.captureException(error);
}
}
Expand Down
17 changes: 17 additions & 0 deletions tests/lib/media-location.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jest.mock("@/lib/auth-context", () => ({
}));

import { updateMediaLocation } from "@/lib/media-location";
import { ServerError } from "@/lib/request";

beforeEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -68,6 +69,22 @@ describe("updateMediaLocation", () => {
expect(mockCaptureException).toHaveBeenCalledWith(networkError);
});

it("does not report transient ServerError (5xx) to Sentry", async () => {
mockFetch.mockReturnValueOnce(jsonResponse(502));

await updateMediaLocation(defaultParams);

expect(mockCaptureException).not.toHaveBeenCalled();
});

it("does not report a directly thrown ServerError to Sentry", async () => {
mockFetch.mockRejectedValueOnce(new ServerError(500, "Request failed: 500"));

await updateMediaLocation(defaultParams);

expect(mockCaptureException).not.toHaveBeenCalled();
});

it("does not throw on failure (non-critical sync)", async () => {
mockFetch.mockRejectedValueOnce(new Error("boom"));

Expand Down
Loading