{"record":{"id":"1ab5f646c539c86f","repo":"antiwork/gumroad","slug":"something-went-wrong-1ab5f6","errorCode":null,"errorMessage":"Something went wrong.","messagePattern":"Something went wrong\\.","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/data/product_reviews.ts","lineNumber":79,"sourceCode":"  created_at: string;\n  is_new: boolean;\n  response: {\n    message: string;\n  } | null;\n  video: {\n    id: string;\n    thumbnail_url: string | null;\n  } | null;\n};\n\nexport const getReviews = async (productId: string, page: number) => {\n  const response = await request({\n    method: \"GET\",\n    url: Routes.product_reviews_path({ product_id: productId, page }),\n    accept: \"json\",\n  });\n\n  if (!response.ok) throw new ResponseError();\n\n  return typia.assert<{ reviews: Review[]; pagination: PaginationProps }>(await response.json());\n};\n\nexport const getReview = async (reviewId: string): Promise<{ review: Review }> => {\n  const response = await request({\n    method: \"GET\",\n    url: Routes.product_review_path(reviewId),\n    accept: \"json\",\n  });\n\n  if (!response.ok) throw new ResponseError();\n\n  return typia.assert<{ review: Review }>(await response.json());\n};\n\nexport const getStreamingUrls = async (id: string) => {\n  const response = await request({","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/data/product_reviews.ts#L61-L97","documentation":"ResponseError ('Something went wrong.') thrown at product_reviews.ts:79 when the GET to Routes.product_reviews_path({ product_id, page }) returns non-ok — a 4xx, since 5xx/429/network are converted inside request(). This lists a product's reviews with pagination; the failure means the endpoint rejected the product/page combination, and the generic message hides which.","triggerScenarios":"404 when productId doesn't resolve to a product (typo, deleted, unpublished — reviews of unpublished products are not public); 422/400 when page is malformed (0, negative, non-numeric from a bad URL param); 401/403 when the endpoint demands a session (e.g., for a non-public product) and the visitor is anonymous.","commonSituations":"Reviews component on a stale product page after the seller unpublished; pagination links built from scraped or malformed URLs feeding garbage page values; product id passed where the route expects the product's permalink, mismatching after an identifier scheme change; crawlers walking ?page=999999999 hitting server-side page guards.","solutions":["Check the GET status in DevTools: 404 → bad product id, other 4xx → page/session","Clamp/normalize page to a positive integer before calling (see validationCode)","Source productId from the loaded page data, not from window.location or a loosely parsed query param","If 404 recurs for an existing product, confirm the route helper receives the identifier the controller expects (id vs permalink)","Treat a failed reviews fetch as non-fatal: render the product page without reviews rather than erroring the whole page"],"exampleFix":"// before\nexport const getReviews = async (productId: string, page: number) => {\n  const response = await request({ method: 'GET', url: Routes.product_reviews_path({ product_id: productId, page }), accept: 'json' });\n  if (!response.ok) throw new ResponseError();\n  // ...\n};\n\n// after\nif (!response.ok) {\n  const body = await response.json().catch(() => null) as { error?: string } | null;\n  throw new ResponseError(body?.error ?? `Failed to load reviews (${response.status})`);\n}","handlingStrategy":"try-catch","validationCode":"const validReviewQuery = (productId: string, page: number): boolean =>\n  productId.length > 0 && Number.isInteger(page) && page >= 1;","typeGuard":"import { assertResponseError } from '$app/utils/request';\nassertResponseError(e);","tryCatchPattern":"try {\n  return await getReviews(productId, page);\n} catch (e) {\n  assertResponseError(e);\n  return { reviews: [], pagination: emptyPagination }; // reviews are supplementary — degrade, don't block\n}","preventionTips":["Clamp page to a positive integer before calling","Treat review-list failure as non-fatal for the product page","Source productId from loaded page data, not from loose URL parsing"],"tags":["reviews","http-404","pagination","product-page"],"backgroundTag":"resource-not-found-404","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}