Skip to content

Media Library: retry thumbnail loads on failure (V1)#25785

Draft
jkmassel wants to merge 5 commits into
trunkfrom
bugfix/media-library-thumbnail-retry
Draft

Media Library: retry thumbnail loads on failure (V1)#25785
jkmassel wants to merge 5 commits into
trunkfrom
bugfix/media-library-thumbnail-retry

Conversation

@jkmassel

@jkmassel jkmassel commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes a bug where images intermittently fail to load in the Media Library (the V1 / UIKit grid — the one that ships in Release). SiteMediaCollectionCellViewModel gave 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 called didFinishLoading(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 — new init parameter, so it's configurable. Default is 3 retries after the initial attempt (4 attempts total).
  • Exponential backoff — 0.5s / 1s / 2s between attempts (capped at 8s), so a transient failure has time to clear instead of immediately failing again.
  • Cancellation-safe — on 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-format pass 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, behind FeatureFlag.mediaLibraryV2, debug-only) has related gaps — it passes no MediaHost for 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

  • Open the Media Library on a WordPress.com or self-hosted site with several images.
  • Induce transient failures — e.g. toggle airplane mode, or set Network Link Conditioner to a lossy profile, while scrolling — and confirm blank cells now fill in on their own within a few seconds instead of staying grey.
  • Confirm normal loading, prefetching, and scrolling are unaffected on a healthy network.
  • Scroll quickly through a large library and confirm cells that scroll away don't keep retrying (cancellation still cancels in-flight loads).

Note

Draft: compiles locally — WordPress scheme builds for the iOS Simulator (** BUILD SUCCEEDED **), and swift-format + SwiftLint pass. Still pending on-device testing of the failure/retry path.

jkmassel added 2 commits July 14, 2026 22:00
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.
@dangermattic

Copy link
Copy Markdown
Collaborator
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

@wpmobilebot

wpmobilebot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number33169
VersionPR #25785
Bundle IDorg.wordpress.alpha
Commita4337d7
Installation URL6g8e5lks297s0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

wpmobilebot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number33169
VersionPR #25785
Bundle IDcom.jetpack.alpha
Commita4337d7
Installation URL1i2s1b5j7ri90
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

jkmassel added 3 commits July 15, 2026 10:48
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
jkmassel force-pushed the bugfix/media-library-thumbnail-retry branch from a6142a6 to a4337d7 Compare July 15, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants