{"record":{"id":"d3167b4695f4d793","repo":"antiwork/gumroad","slug":"something-went-wrong-d3167b","errorCode":null,"errorMessage":"Something went wrong.","messagePattern":"Something went wrong\\.","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/data/price_distribution.ts","lineNumber":68,"sourceCode":"  name: string;\n  description: string;\n  taxonomy_id: string | null;\n  native_type: string;\n  currency_code: string;\n};\n\nexport const fetchPriceDistribution = async (\n  uniquePermalink: string,\n  { refresh = false, overrides, signal }: { refresh?: boolean; overrides: PriceCheckOverrides; signal?: AbortSignal },\n): Promise<PriceDistribution> => {\n  const response = await request({\n    method: \"POST\",\n    accept: \"json\",\n    url: Routes.price_check_product_path(uniquePermalink),\n    data: { refresh, overrides },\n    abortSignal: signal,\n  });\n  if (!response.ok) throw new ResponseError();\n  return typia.assert<PriceDistribution>(await response.json());\n};\n","sourceCodeStart":50,"sourceCodeEnd":71,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/data/price_distribution.ts#L50-L71","documentation":"ResponseError ('Something went wrong.') thrown at price_distribution.ts:68 when the POST to Routes.price_check_product_path(uniquePermalink) — the pay-what-you-want price-distribution check sent with { refresh, overrides } and an optional abort signal — returns non-ok (a 4xx; 5xx/429/network are handled inside request()). The endpoint computes the price histogram for a product so the buyer can sanity-check their offer; a 4xx means the permalink or the override values were rejected.","triggerScenarios":"404 when uniquePermalink does not match a live product (typo, deleted, unpublished, or a permalink from another environment); 422 when the overrides object contains values the server rejects (non-positive amount, minimum greater than maximum, unsupported currency, or an offer below a set floor); 401/403 when the check requires a session that has expired.","commonSituations":"Price check fired on a product page kept open after the seller unpublished it; overrides built from a form whose fields were emptied (amount=NaN → serialized as null → 422); multiple rapid edits triggering overlapping checks — stale ones are aborted via signal, but a permanently bad permalink keeps 404ing; heavy refresh=true polling from a stuck UI eventually hitting the 429 path (which surfaces as RateLimitError, not this error).","solutions":["Read the status in DevTools for the price_check POST: 404 points at the permalink, 422 at the overrides","Validate overrides before calling: positive finite amount, min<=max, and required fields present (see validationCode below)","Verify uniquePermalink comes from the currently loaded product, not from a cached or shared URL","Keep passing the AbortSignal from the UI component so superseded checks cancel before they can fail","If refresh=true flows hit RateLimitError, respect retryAfter instead of hammering refresh"],"exampleFix":"// before\nif (!response.ok) throw new ResponseError();\n\n// after\nif (!response.ok) {\n  const body = await response.json().catch(() => null) as { error?: string } | null;\n  throw new ResponseError(body?.error ?? `Price check failed (${response.status})`);\n}","handlingStrategy":"validation","validationCode":"const validOverrides = (o: PriceCheckOverrides): boolean =>\n  Number.isFinite(o.amount) && o.amount > 0 && (o.min == null || o.max == null || o.min <= o.max);","typeGuard":"import { RateLimitError, assertResponseError } from '$app/utils/request';\n// distinguishes 'wait' (429) from a real failure\nif (e instanceof RateLimitError) { /* wait e.retryAfter seconds */ } else { assertResponseError(e); }","tryCatchPattern":"try {\n  return await fetchPriceDistribution(permalink, { overrides, refresh, signal });\n} catch (e) {\n  if (e instanceof RateLimitError) return scheduleRetry(e.retryAfter);\n  assertResponseError(e);\n  return null; // price hint is optional UI — degrade gracefully\n}","preventionTips":["Validate override values before posting (positive amount, min<=max)","Pass the AbortSignal so superseded checks cancel instead of racing","Rate-limit the refresh button client-side; the server's 429 arrives as RateLimitError with retryAfter"],"tags":["pwyw","price-check","http-4xx","product-page"],"backgroundTag":"http-4xx-client-error","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}