Skip to content

fix(mobile): wire mirror retry to drawer profile picture#14349

Merged
raymondjacobson merged 1 commit into
mainfrom
claude/mobile-profile-picture-mirror-retry
May 18, 2026
Merged

fix(mobile): wire mirror retry to drawer profile picture#14349
raymondjacobson merged 1 commit into
mainfrom
claude/mobile-profile-picture-mirror-retry

Conversation

@raymondjacobson
Copy link
Copy Markdown
Member

Summary

Fixes reports of the left-drawer profile picture not loading on mobile.

The drawer's <ProfilePicture /> was dropping the onError callback returned by useProfilePicture, so render-time image failures never reached useImageSize — the mirror retry could only fire on prefetch failures. A slow Open Audio Validator Node that accepted the prefetch but stalled the actual render would leave the avatar hung indefinitely (the OS TCP timeout is 60–90s with no onError fired).

Changes

  • ProfilePicture — forward onError (chained with the caller's), pass priorityLowResSource through, and set timeoutMs={3000} so stalled URLs advance to the next mirror.
  • UserImage — add matching timeoutMs={3000} for parity.
  • harmony-native Image — add optional timeoutMs prop (default 0 = disabled, preserving existing behavior everywhere else). When > 0 and the source is a remote URI, synthesize an onError if neither onLoad nor onError fires within the window. Mirrors the web MirrorImage pattern.
  • Artwork — plumb timeoutMs through so Avatar → Artwork → Image is wired end-to-end.

Why this works

useImageSize already has all the mirror-retry logic: it tracks failedUrls, swaps in the next mirror's hostname via getNextMirrorUrl, and re-renders. It just needed render-time failures (including timeouts) to be reported back. With the timeoutMs={3000} opt-in, hung connections become synthetic onErrors after 3s, matching the global pattern documented for the web client.

The fix is scoped: harmony Image's default is timeoutMs={0} (off), so unrelated image usages across the app keep their existing semantics.

Test plan

  • Open the app on mobile (cold start), open the left drawer, confirm the avatar loads
  • Throttle a content node hostname locally (e.g. via Charles / hosts file → blackhole) and confirm the avatar still resolves via a mirror within ~3s instead of hanging
  • Confirm track tiles, playlist artwork, and other Artwork/Image usages render normally (they default to timeoutMs=0, so behavior is unchanged)
  • Confirm progressive loading still works (low-res placeholder → high-res crossfade) for profile pictures

🤖 Generated with Claude Code

ProfilePicture dropped the `onError` callback returned by
`useProfilePicture`, so render-time image failures never reached
`useImageSize` — the mirror retry could only fire on prefetch failures.
A slow validator node that accepted the prefetch but stalled the actual
render would leave the avatar hung indefinitely (OS TCP timeout is
60–90s with no `onError` fired).

Changes:
- `ProfilePicture`: forward `onError` (chained with caller's), pass
  `priorityLowResSource`, and set `timeoutMs={3000}` so stalled URLs
  advance to the next mirror.
- `UserImage`: add matching `timeoutMs={3000}` for parity.
- Harmony-native `Image`: add optional `timeoutMs` prop (default 0/off).
  When >0 and source is a remote URI, synthesize an `onError` if neither
  `onLoad` nor `onError` fires in the window. Mirrors the web
  `MirrorImage` pattern.
- `Artwork`: plumb `timeoutMs` through so `Avatar → Artwork → Image`
  wires it end-to-end.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 18, 2026

⚠️ No Changeset found

Latest commit: 3847380

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@raymondjacobson raymondjacobson merged commit c93a265 into main May 18, 2026
3 checks passed
@raymondjacobson raymondjacobson deleted the claude/mobile-profile-picture-mirror-retry branch May 18, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant