fix(profile): fetch full profile for avatar decoration to avoid 404 spam
CI / Build & Quality Checks (push) Successful in 10m46s
CI / Trigger Desktop Build (push) Successful in 19s

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 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 20:28:40 -04:00
parent 4236621c7a
commit 1b2142e6c4
+8 -7
View File
@@ -29,7 +29,11 @@ function fetchDecoration(
const waiters: Array<(val: string | null) => void> = []; const waiters: Array<(val: string | null) => void> = [];
pending.set(userId, waiters); 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) => { .then((res) => {
const val = (res[PROFILE_FIELD] as string | undefined) ?? null; const val = (res[PROFILE_FIELD] as string | undefined) ?? null;
cache.set(userId, val); cache.set(userId, val);
@@ -37,12 +41,9 @@ function fetchDecoration(
}) })
.catch((err: unknown) => { .catch((err: unknown) => {
const status = err instanceof MatrixError ? err.httpStatus : undefined; const status = err instanceof MatrixError ? err.httpStatus : undefined;
// Definitive rejections — the field is unset (404) or the server won't // Definitive rejections (404 unknown user / 403 can't view / 400) — cache
// serve it (400/403). This is the common case for FEDERATED users whose // "no decoration" so we never refetch a profile we can't read (otherwise
// homeserver doesn't support extended profiles / rejects the field. Cache // every avatar mount re-floods our HS with failing federated lookups).
// "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).
if (status === 404 || status === 403 || status === 400) { if (status === 404 || status === 403 || status === 400) {
cache.set(userId, null); cache.set(userId, null);
} else { } else {