From 1b2142e6c4fc1732a3624670e20813fec02568b0 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Tue, 7 Jul 2026 20:28:40 -0400 Subject: [PATCH] fix(profile): fetch full profile for avatar decoration to avoid 404 spam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useAvatarDecoration GET /profile/{user}/io.lotus.avatar_decoration returns 404 for every user without a decoration (most users), which the browser logs as a failed request — a console 404 per member. Fetch the whole profile (GET /profile/{user}, 200 with all MSC4133 fields) and read the decoration field out of it instead. Same negative-caching behavior; no functional change, just no 404 storm. Co-Authored-By: Claude Opus 4.8 --- src/app/hooks/useAvatarDecoration.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/app/hooks/useAvatarDecoration.ts b/src/app/hooks/useAvatarDecoration.ts index 86f0f975d..0ecdc56ff 100644 --- a/src/app/hooks/useAvatarDecoration.ts +++ b/src/app/hooks/useAvatarDecoration.ts @@ -29,7 +29,11 @@ function fetchDecoration( const waiters: Array<(val: string | null) => void> = []; pending.set(userId, waiters); - return authedRequest(Method.Get, `/profile/${encodeURIComponent(userId)}/${PROFILE_FIELD}`) + // Fetch the WHOLE profile, not the single `/{field}` sub-resource: an unset + // field returns 404, which the browser logs as a failed request — a console + // 404 for every user without a decoration. The full profile returns 200 with + // all fields (incl. custom MSC4133 ones); read the decoration out of it. + return authedRequest(Method.Get, `/profile/${encodeURIComponent(userId)}`) .then((res) => { const val = (res[PROFILE_FIELD] as string | undefined) ?? null; cache.set(userId, val); @@ -37,12 +41,9 @@ function fetchDecoration( }) .catch((err: unknown) => { const status = err instanceof MatrixError ? err.httpStatus : undefined; - // Definitive rejections — the field is unset (404) or the server won't - // serve it (400/403). This is the common case for FEDERATED users whose - // homeserver doesn't support extended profiles / rejects the field. Cache - // "no decoration" so we never refetch: otherwise every avatar mount - // re-requests and floods our homeserver with failing federated profile - // lookups (the 403/502 console storm + real HS load). + // Definitive rejections (404 unknown user / 403 can't view / 400) — cache + // "no decoration" so we never refetch a profile we can't read (otherwise + // every avatar mount re-floods our HS with failing federated lookups). if (status === 404 || status === 403 || status === 400) { cache.set(userId, null); } else {