{"record":{"id":"9bfb7fa40a1608fa","repo":"antiwork/gumroad","slug":"sorry-something-went-wrong-please-try-again-9bfb7f","errorCode":null,"errorMessage":"Sorry, something went wrong. Please try again.","messagePattern":"Sorry, something went wrong\\. Please try again\\.","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/data/wishlists.ts","lineNumber":131,"sourceCode":"    url: Routes.wishlist_path(wishlistId),\n    accept: \"json\",\n  });\n  if (!response.ok) throw new ResponseError();\n};\n\nexport const deleteWishlistItem = async ({\n  wishlistId,\n  wishlistProductId,\n}: {\n  wishlistId: string;\n  wishlistProductId: string;\n}) => {\n  const response = await request({\n    method: \"DELETE\",\n    url: Routes.wishlist_product_path(wishlistId, wishlistProductId),\n    accept: \"json\",\n  });\n  if (!response.ok) throw new ResponseError();\n};\n\nexport const followWishlist = async ({ wishlistId }: { wishlistId: string }) => {\n  const response = await request({\n    method: \"POST\",\n    url: Routes.wishlist_followers_path(wishlistId),\n    accept: \"json\",\n  });\n  if (!response.ok) {\n    const data = typia.assert<{ error: string }>(await response.json());\n    throw new ResponseError(data.error);\n  }\n};\n\nexport const unfollowWishlist = async ({ wishlistId }: { wishlistId: string }) => {\n  const response = await request({\n    method: \"DELETE\",\n    url: Routes.wishlist_followers_path(wishlistId),","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/data/wishlists.ts#L113-L149","documentation":"deleteWishlistItem (app/javascript/data/wishlists.ts:119-132) DELETEs Routes.wishlist_product_path(wishlistId, wishlistProductId) and throws generic ResponseError ('Something went wrong.') on !response.ok; the wishlist page's catch (components/Wishlist/index.tsx:106-108) shows the listed message 'Sorry, something went wrong. Please try again.'. With 5xx/429/network pre-handled in request(), this is a 4xx: 404 (item already removed — stale card, second tab), 403 (viewer can't edit), 401 (expired session).","triggerScenarios":"Clicking the trash icon on a wishlist item that was already removed in another tab (404); deleting from a wishlist the user can no longer edit (403); double-clicking remove so the second DELETE 404s; session expiring before the click (401).","commonSituations":"Multi-tab wishlist editing; back-navigation to a stale rendered list; the isDeleting flag in index.tsx not yet disabling the button on slow networks; tests deleting the same fixture item twice.","solutions":["Refresh the wishlist — the removed item disappears and the goal state is reached","Keep the per-card isDeleting guard (index.tsx:97-100) so double clicks can't fire two DELETEs","Confirm canEdit was true when rendering the delete affordance","Check the DELETE's status in the network tab; treat 404 as already-removed"],"exampleFix":"// components/Wishlist/index.tsx — reconcile on failure instead of only toasting\n} catch (e) {\n  assertResponseError(e);\n  showAlert(\"Sorry, something went wrong. Please try again.\", \"error\");\n  void refreshItems(); // if it 404'd because it's gone, the list converges\n}","handlingStrategy":"try-catch","validationCode":"const itemInState = (itemId: string, items: WishlistItem[]) => items.some((i) => i.id === itemId);\nif (!itemInState(item.id, items)) return; // already removed elsewhere","typeGuard":"const isResponseError = (e: unknown): e is ResponseError => e instanceof ResponseError;","tryCatchPattern":"try {\n  await deleteWishlistItem({ wishlistId, wishlistProductId: item.id });\n  onDelete();\n} catch (e) {\n  assertResponseError(e);\n  showAlert(\"Sorry, something went wrong. Please try again.\", \"error\");\n  void refreshItems(); // if it 404'd because it's gone, the list converges\n}","preventionTips":["Keep the isDeleting per-card guard so double clicks can't fire two DELETEs","Only render the trash affordance when canEdit is true","Treat already-removed as success and refresh from server truth"],"tags":["wishlists","http","delete","idempotency","fetch"],"backgroundTag":"http-404-not-found","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}