Media Library: retry thumbnail loads on failure (V1)#25785
Draft
jkmassel wants to merge 5 commits into
Draft
Conversation
Whitespace and line-wrapping only, no behavior change. Split from the retry change so the logic diff reviews cleanly.
The media library cell gave up after a single failed thumbnail download, leaving a blank placeholder until the cell was scrolled off-screen and reconfigured. Transient failures (network blips, a CDN 5xx, a truncated response that fails to decode) are common, so one failure presented as a permanently missing thumbnail. SiteMediaCollectionCellViewModel now retries the load up to retryCount times (default 3, configurable via init) with exponential backoff (0.5s/1s/2s, capped at 8s). Cancelled requests -- cell scrolled away, deinit, prefetch cancelled -- neither retry nor report a failure.
Collaborator
Generated by 🚫 Danger |
Contributor
|
| App Name | WordPress | |
| Configuration | Release-Alpha | |
| Build Number | 33169 | |
| Version | PR #25785 | |
| Bundle ID | org.wordpress.alpha | |
| Commit | a4337d7 | |
| Installation URL | 6g8e5lks297s0 |
Contributor
|
| App Name | Jetpack | |
| Configuration | Release-Alpha | |
| Build Number | 33169 | |
| Version | PR #25785 | |
| Bundle ID | com.jetpack.alpha | |
| Commit | a4337d7 | |
| Installation URL | 1i2s1b5j7ri90 |
P2 (WP-for-Teams) blogs report `isPrivate == false`, so media thumbnails were routed through Photon (a public image CDN) with no auth token, which returns 403 for the private originals. Treat WP-for-Teams blogs as private for media hosting so they skip Photon and send the bearer token.
Thumbnail load failures were silently swallowed, which made issues like the private-P2 403s impossible to diagnose from logs. Capture the requested URL, the routing flags that produced it, and the underlying error on failure (`.error`), plus the resolved load source per thumbnail (`.debug`).
A fatal client error (a 4xx such as 403 or 404) won't recover on retry, so give up immediately instead of spending the retry budget on it. 408 (timeout) and 429 (rate limited) are transient and keep retrying with backoff.
jkmassel
force-pushed
the
bugfix/media-library-thumbnail-retry
branch
from
July 15, 2026 17:14
a6142a6 to
a4337d7
Compare
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.


Description
Fixes a bug where images intermittently fail to load in the Media Library (the V1 / UIKit grid — the one that ships in Release).
SiteMediaCollectionCellViewModelgave up after a single failed thumbnail download, leaving a blank grey placeholder until the cell was scrolled off-screen and reconfigured. Transient failures — a network blip, a CDN 5xx, a truncated response that fails to decode, or a request cancelled by fast scrolling — are common, so one failure presented as a permanently missing thumbnail.Root Cause
SiteMediaCollectionCellViewModel.fetchThumbnailIfNeeded()ran the load exactly once; on any error it calleddidFinishLoading(with: nil)— no retry, no error affordance. Because a failed load renders identically to the loading placeholder, the cell just stays grey. The only recovery path was cell reuse: scroll the cell away and back →configure→ refetch.Fix
The load task is now a retry loop:
retryCount: Int = 3— newinitparameter, so it's configurable. Default is 3 retries after the initial attempt (4 attempts total).Task.isCancelled(cell scrolled away,deinit, prefetch cancelled) the loop returns immediately: no retry, no failure state, no wasted downloads. The final give-up behavior is unchanged (didFinishLoading(with: nil)).Because each retry re-enters
MediaImageService.image(for:)— which re-checks the memory → disk → local-thumbnail chain — a retry also naturally picks up a local thumbnail or cache entry that became available in the meantime.Split into two commits — a
swift-formatpass on the file, then the retry logic — so the behavioral change reviews cleanly.Scope: V1 only, as a first step. The V2 SwiftUI grid (
WordPressMediaLibrary, behindFeatureFlag.mediaLibraryV2, debug-only) has related gaps — it passes noMediaHostfor auth, and renders a failed download as the loading placeholder — that are a separate effort. The V1 detail/preview (SiteMediaImageLoadingController) shares the same no-retry gap and is also left for follow-up.Testing instructions
Note
Draft: compiles locally —
WordPressscheme builds for the iOS Simulator (** BUILD SUCCEEDED **), andswift-format+ SwiftLint pass. Still pending on-device testing of the failure/retry path.