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 {