antiwork/gumroad · error · ResponseError

An error occurred while loading more items

Error message

An error occurred while loading more items

What it means

fetchPaginatedWishlistItems (app/javascript/data/wishlists.ts:41-52) GETs Routes.wishlist_products_path(wishlist_id, { page }) and throws generic ResponseError when response.ok is false; the infinite-scroll loader in components/Wishlist/index.tsx:198-214 catches it and toasts 'An error occurred while loading more items'. With 5xx/429/network handled upstream in request(), this is a 4xx: 404 (wishlist deleted or removed from public view, or page beyond range), 401 (session), 403 (private wishlist).

Source

Thrown at app/javascript/data/wishlists.ts:50

    items: number;
    page: number;
    pages: number;
    prev: number | null;
    next: number | null;
    last: number;
  };
};

export const fetchPaginatedWishlistItems = async ({
  wishlist_id,
  page,
}: FetchPaginatedWishlistItemsArgs): Promise<PaginatedWishlistItems> => {
  const response = await request({
    method: "GET",
    accept: "json",
    url: Routes.wishlist_products_path(wishlist_id, { page }),
  });
  if (!response.ok) throw new ResponseError();
  return typia.assert<PaginatedWishlistItems>(await response.json());
};

export const addToWishlist = async ({
  wishlistId,
  productId,
  optionId,
  recurrence,
  rent,
  quantity,
}: {
  wishlistId: string;
  productId: string;
  optionId: string | null;
  recurrence: string | null;
  rent: boolean;
  quantity: number | null;
}) => {

View on GitHub (pinned to afeacbd394)

Solutions

  1. Reload the wishlist page — if the wishlist is gone the server-rendered load will show it, ending the loop
  2. Verify pagination.next is non-null before fetching (index.tsx:218 already gates the observer on it)
  3. On failure, stop the infinite scroll rather than retrying the same page forever
  4. Check the GET's status in the network tab to distinguish deleted (404) from expired session (401)

Example fix

// components/Wishlist/index.tsx — stop the observer after a failure instead of looping
const [loadFailed, setLoadFailed] = React.useState(false);
if (e) { /* in catch */
  assertResponseError(e);
  showAlert("An error occurred while loading more items", "error");
  setLoadFailed(true);
}
// gate: if (e[0]?.isIntersecting && !loadingMore && !loadFailed && pagination.next) ...
Defensive patterns

Strategy: try-catch

Validate before calling

const shouldLoadMore = pagination.next !== null && !loadingMore && !loadFailed;
if (!shouldLoadMore) return; // index.tsx:218 already gates on pagination.next

Type guard

const isResponseError = (e: unknown): e is ResponseError => e instanceof ResponseError;

Try / catch

try {
  const loaded = await fetchPaginatedWishlistItems({ wishlist_id: id, page: pagination.next });
  setItems((prev) => uniqBy([...prev, ...loaded.items], "id"));
} catch (e) {
  assertResponseError(e);
  setLoadFailed(true); // stop the IntersectionObserver from retrying forever
  showAlert("An error occurred while loading more items", "error");
}

Prevention

When it happens

Trigger: Scrolling a wishlist page to trigger load-more after the wishlist was deleted or made private (404); requesting a page number that no longer exists because items were removed; viewer session expired mid-scroll (401); following a link to a wishlist whose owner blocked access (403).

Common situations: Wishlists edited/deleted while a follower has the page open; pagination state computed from a stale count; offline laptops resuming scroll; tests stubbing only page 1.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/b60b67117f5b74be. Report an issue: GitHub.