Skip to content

Festivals page hangs on infinite "Loading festivals…" when Supabase is unreachable (no timeout / error state) #56

Description

@chiptus

Problem

When the Supabase backend is unreachable (e.g. a paused project on a preview/free-tier deployment, network failure, or DNS/CORS issue), FestivalSelection shows the "Loading festivals…" spinner forever with no way to recover and no indication anything went wrong.

Discovered on the Vercel preview for #54: the festivals list never appeared. Root cause was a paused Supabase project — the from("festivals").select() request opened and never received a response, so the query promise never settled. Confirmed it was not the #54 refactor (the festivals query is behavior-identical before/after the move).

Why it hangs instead of erroring

src/pages/FestivalSelection.tsx only branches on isLoading:

const { data: availableFestivals = [], isLoading: festivalsLoading } = useFestivalsQuery();
if (festivalsLoading) return <Spinner text="Loading festivals…" />;
  • A request that errors flips isLoading → false, so the page falls through to the empty/list state — handled.
  • A request that never settles (unreachable backend, no response) keeps isLoading === true indefinitely. TanStack Query can't retry a promise that never rejects, so the spinner is permanent.

There is no query timeout and no isError branch, so an unreachable backend is indistinguishable from "still loading."

Proposed fix

  1. Surface errors in FestivalSelection — add an isError branch with a readable message ("Couldn't load festivals — retry") and a retry button, instead of only handling isLoading.
  2. Bound the request so a hung backend eventually fails instead of hanging forever — e.g. an AbortSignal.timeout(...) passed to the Supabase call in fetchFestivals (and ideally the other top-level fetches), or a query-level timeout, so it transitions to isError and becomes retryable.
  3. Consider applying the same pattern to the other route loaders/queries that can hang on an unreachable backend (festival-by-slug, editions), since they share the failure mode.

Scope / notes

Acceptance

  • An unreachable/paused backend results in a visible error state with retry within a bounded time, not a permanent spinner.
  • Normal load and empty ("No Festivals Available") states are unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions