Skip to content

WMS layer auto-refresh on tile load error has no retry limit, can loop forever under recurring/load-dependent failures #12688

Description

@offtherailz

Description

When a WMS layer's loadingError state transitions from no-error to "Error", WMSLayer.js (openlayers plugin, update function) unconditionally calls wmsSource.refresh(), which drops the tile cache and re-requests every currently visible tile. This is meant to help recover from a one-off configuration mistake (per the existing code comment, e.g. "incorrect time dimension date filter") that gets fixed externally, where one automatic reload picks up the corrected data. It has no attempt counter and no cooldown.

The trigger itself is generic (it fires whenever loadingError flips from anything else to "Error", for any tile load failure — no security/authentication configuration required), but note the loop specifically requires the error state to oscillate (fail, then recover, then fail again), not just fail once permanently — the check only reacts to a false → true transition, so a layer that fails deterministically and stays failed only triggers one refresh(), not a loop. The loop shows up when the underlying failure is intermittent: something that fails sometimes and not other times for the same layer/tile (e.g. a security/auth check with an occasional race condition, or a backend with a short timeout and limited concurrency that can't always keep up with a full-viewport burst of concurrent tile requests). In that situation, the refresh()'s own fresh burst of tile requests recreates the same conditions that caused the original failure, so it has a real chance of failing again — flipping loadingError to "Error" again, triggering another refresh(), and so on. Visually the layer flashes/reloads without ever settling, and the browser keeps sending WMS requests indefinitely.

How to reproduce

This requires a WMS backend that intermittently fails a fraction of concurrent tile requests (not a permanently broken layer, which only triggers the refresh once and then stays in a stable error state). We reproduced it against a real backend under the following conditions:

  • A secured WMS layer (tiles carry an auth token as a URL parameter, validated server-side).
  • The security check occasionally fails validation for a token that is valid moments later (session/timing-dependent, not a fixed misconfiguration).
  • Loading the map at a zoom level that requests 10+ tiles concurrently, so each reload attempt has multiple chances to hit the intermittent failure.

Expected Result
A tile load failure should trigger at most a small, bounded number of automatic layer refreshes. If the failure keeps recurring, MapStore should stop auto-refreshing and leave the tile(s) in a visibly-errored state rather than retrying forever.

Current Result
Every time loadingError flips to "Error" again, wmsSource.refresh() fires again, unconditionally, with no limit. Reproduced against a real intermittently-failing backend: the same ~16 tiles for one layer were re-requested upwards of 170 times within 20 seconds, with the refresh() call itself observed firing 56 times consecutively in a single session (confirmed via added instrumentation logging, not inferred from network traffic alone).

  • Not browser related
Browser info
Browser Affected Version
Chrome 150 (also expected on any browser, mechanism is not browser-specific)

Other useful information

Relevant code: web/client/components/map/openlayers/plugins/WMSLayer.js, update function:

// refresh/update wms layer if there is error in loading tiles like: incorrect time dimension date filter, ..etc
if (oldOptions.loadingError !== "Error" && newOptions.loadingError === "Error") {
    wmsSource?.tileCache?.pruneExceptNewestZ?.();
    wmsSource?.refresh();
}

Suggested fix: track consecutive auto-refresh attempts per layer within a cooldown window (e.g. max 3 attempts per 30s, counter reset only after a real quiet period — not on every transient recovery, since the loop itself involves the error state oscillating rapidly, which would otherwise reset the counter before it ever caps). PR to follow.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions