fix(web): stop a single image error from permanently blanking an avatar - #14586
Merged
Conversation
Avatar tracked image failures in a boolean `hasError` that only reset when `userId` changed, so the first <img> error swapped in the empty-avatar placeholder for the life of the mount. useImageSize does resolve a working mirror after a failure, but Avatar discarded it — the placeholder had already won — which is why verified artists with perfectly good profile pictures render a gray silhouette in search. The trigger is the API handing out a content node that 502s for the blob (~5% of profile-picture primaries at the moment; the shuffle in rendezvous.Select re-rolls the primary per request, so the same user shows up broken for some sessions and fine for others). A transient failure under a burst of cards does it too. Track the failing src instead of a boolean, so a later mirror url renders normally, and forward the error to useImageSize.onError so it advances to the next mirror rather than leaving the image stranded on a dead host. Once every mirror has failed the placeholder sticks, and since it is a data uri it cannot error and re-enter the retry path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Reported in Slack: "some profile images aren't showing in search for people that have them" — RAC, MR•CAR/\ACK and Critical Music all rendering the gray silhouette.
Reproduced on
audius.co/search/profiles?query=beats: @lofibeat renders the placeholder, but their profile picture (QmY685fLjPvG3Ve75TZ9FaMsbVpDb5voRnTzkF5VqRytEf) returns 200 from all four hosts the API lists for it. The image is fine — the client blanked it.Cause
Avatarlatched image failures in a boolean that only reset whenuserIdchanged:useImageSizerenders the primary url optimistically, then preloads it and swaps in a working mirror if it fails. The two race: if the mounted<img>firesonErrorfirst,hasErrorflips and the mirroruseImageSizesubsequently resolves is thrown away for the rest of the mount. The mirror machinery works;Avatarjust discarded its result.UserArtCardon the explore page has the mirror-image bug — it passes noonErrorat all, souseImageSize's own retry path never fires there either. Left for a follow-up; it isn't the reported surface.What sets it off
The API hands out content nodes that answer
/health_checkbut 502/503 on the blob. Six registered nodes currently fail on 100% of content I sampled (cn1/cn3/cn4.mainnet.audiusindex.org,validator.stuffisup.com,audius-nodes.com,audius.zeogrid.com), and 38 of 719 sampled profile-picture primaries (5.3%) pointed at one.rendezvous.Selectre-shuffles the primary per request, so the same artist is broken for some sessions and fine for others — RAC drawsvalidator.stuffisup.comas primary in roughly 1 in 6 responses. A transient failure under a burst of cards (as with @lofibeat, whose hosts are all healthy) does it too.A separate
apichange to blacklist those nodes is worth doing, but this fix is what makes the client survive a bad host at all.Fix
Track the failing
srcrather than a boolean, so a later mirror url renders normally, and forward the error touseImageSize'sonErrorso it advances to the next mirror. Once every mirror has failed the placeholder sticks — and since it's a data uri it can't error and re-enter the retry path, so this terminates.Testing
UserCardregression test: fails onmain(× retries a mirror when the primary host fails to render), passes with the fix. Full file 5/5.tscclean,eslintclean on the touched files.beatssearch that reproduced the bug: 24 cards, zero placeholders, including @lofibeat.🤖 Generated with Claude Code