Skip to content

Campaign dialogs never receive world list: StrictMode abort poisons shared world-map cache #38

Description

@barrulus

Symptom

Create/Edit Campaign dialogs show "No world maps available" even though GET /api/maps/world returns worlds. No error toast. Refresh does not reliably fix it.

Root cause

The app runs in React StrictMode (dev double-mount). components/campaign-manager/use-world-maps.ts starts the fetch on mount 1 and aborts it on the immediate StrictMode unmount. utils/world-map-cache.ts shares one in-flight promise across callers, and that shared request is bound to the first caller's AbortSignal — so mount 2 joins the already-aborted request, receives AbortError, and the hook swallows AbortError (use-world-maps.ts:36) without retrying. Empty list, no toast, no refetch. It is a race: when the API responds before StrictMode unmounts, everything works, which is why it is intermittent (cold/slow API loses the race).

Fix

A shared cache request must not be tied to one consumer's abort signal. In utils/world-map-cache.ts:

const request = listWorldMapsFetcher({})   // was: listWorldMapsFetcher({ signal })

Consumers that unmount simply ignore the result; the cache still populates for the next opener. Optionally also: on AbortError rejection do not store it in cache.error.

Found while browser-testing the lazy-world-tiles branch (2026-08-10); pre-existing, unrelated to that branch (code last touched in the campaign-manager decomposition refactor, commit 744d4d7).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions