diff --git a/apps/web/src/components/pullRequest/pullRequestPresentation.test.tsx b/apps/web/src/components/pullRequest/pullRequestPresentation.test.tsx
new file mode 100644
index 000000000000..df38d75152cf
--- /dev/null
+++ b/apps/web/src/components/pullRequest/pullRequestPresentation.test.tsx
@@ -0,0 +1,28 @@
+import { act } from "react";
+import { create, type ReactTestRenderer } from "react-test-renderer";
+import { afterEach, expect, it, vi } from "vite-plus/test";
+
+import { PullRequestActorAvatar } from "./pullRequestPresentation";
+
+let renderer: ReactTestRenderer | undefined;
+
+afterEach(async () => {
+ await act(async () => renderer?.unmount());
+ vi.unstubAllGlobals();
+});
+
+it("falls back to the actor initial when a remote avatar fails", async () => {
+ vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
+ await act(async () => {
+ renderer = create(
+ ,
+ );
+ });
+
+ await act(async () => renderer!.root.findByType("img").props.onError());
+
+ expect(renderer!.root.findAllByType("img")).toHaveLength(0);
+ expect(renderer!.root.findByType("span").children).toEqual(["O"]);
+});
diff --git a/apps/web/src/components/pullRequest/pullRequestPresentation.tsx b/apps/web/src/components/pullRequest/pullRequestPresentation.tsx
index 890efb67cb9b..e011fa640311 100644
--- a/apps/web/src/components/pullRequest/pullRequestPresentation.tsx
+++ b/apps/web/src/components/pullRequest/pullRequestPresentation.tsx
@@ -19,7 +19,7 @@ import {
TriangleAlertIcon,
UserCheckIcon,
} from "lucide-react";
-import { Children, isValidElement, type ReactNode } from "react";
+import { Children, isValidElement, type ReactNode, useState } from "react";
import { cn } from "~/lib/utils";
@@ -346,8 +346,9 @@ export function PullRequestActorAvatar({
}) {
const login = actor?.login ?? "ghost";
const avatarUrl = actor?.avatarUrl ?? null;
- return avatarUrl === null ? (
- // Not every host reports an avatar, so the initial stands in where none arrives.
+ const [failedAvatarUrl, setFailedAvatarUrl] = useState(null);
+ return avatarUrl === null || failedAvatarUrl === avatarUrl ? (
+ // Not every host reports an avatar, and a private host may refuse the browser's request.
setFailedAvatarUrl(avatarUrl)}
/>
);
}