{"record":{"id":"a7323d75b50fcdb3","repo":"antiwork/gumroad","slug":"data-error","errorCode":null,"errorMessage":"${data.error}","messagePattern":"\\$\\{data\\.error\\}","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/data/wishlists.ts","lineNumber":85,"sourceCode":"  quantity: number | null;\n}) => {\n  const response = await request({\n    method: \"POST\",\n    url: Routes.wishlist_products_path(wishlistId),\n    accept: \"json\",\n    data: {\n      wishlist_product: {\n        product_id: productId,\n        option_id: optionId,\n        recurrence,\n        rent,\n        quantity,\n      },\n    },\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 updateWishlist = async ({\n  id,\n  ...wishlist\n}: {\n  id: string;\n  name?: string;\n  description?: string | null;\n  discover_opted_out?: boolean;\n}) => {\n  const response = await request({\n    method: \"PUT\",\n    url: Routes.wishlist_path(id),\n    accept: \"json\",\n    data: { wishlist },\n  });","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/data/wishlists.ts#L67-L103","documentation":"addToWishlist (app/javascript/data/wishlists.ts:54-87) POSTs a wishlist_product and, on !response.ok, decodes the body as {error: string} and throws ResponseError(data.error) — the server's message reaches the user. Expect 422-class refusals: product not purchasable/available, invalid quantity or recurrence, product already in the wishlist, or wishlist not editable by this user; also 401/403/404 with an error-bearing body. Called from the product share section (components/Product/ShareSection.tsx:60).","triggerScenarios":"Clicking 'Add to wishlist' on a product page for a product that is unpublished, expired, or not purchasable; adding with quantity 0 or a recurrence the product doesn't support; adding to a wishlist the user can no longer edit; adding the same product twice where duplicates are refused.","commonSituations":"Stale buy buttons on cached product pages after a seller unpublishes; variant/option combinations removed by the seller; wishlists deleted in another tab; tests stubbing the route without an error field.","solutions":["Read e.message — the server states the refusal (availability, quantity, duplicates)","Refresh the product page and retry so availability and options are current","Pick a different wishlist when the error says the current one isn't editable","Note the trap: if the error body isn't exactly {error: string}, typia.assert throws its own error — guard the parse (see exampleFix)"],"exampleFix":"// before\nconst data = typia.assert<{ error: string }>(await response.json());\nthrow new ResponseError(data.error);\n\n// after — don't let a non-envelope error body crash the error path\nconst body: unknown = await response.json().catch(() => null);\nthrow new ResponseError(typia.is<{ error: string }>(body) ? body.error : \"Could not add to wishlist.\");","handlingStrategy":"try-catch","validationCode":"const addable = (p: { productId: string; quantity: number | null }) =>\n  p.productId !== \"\" && (p.quantity === null || p.quantity > 0);\nif (!addable({ productId, quantity })) return showError(\"Pick a product and a valid quantity.\");","typeGuard":"import typia from \"typia\";\nconst hasErrorString = typia.is<{ error: string }>;","tryCatchPattern":"try {\n  await addToWishlist({ wishlistId, productId, optionId, recurrence, rent, quantity });\n} catch (e) {\n  assertResponseError(e);\n  showAlert(e.message, \"error\"); // server's refusal: not purchasable, bad quantity, duplicate\n}","preventionTips":["Verify the product is still purchasable (fresh page) before showing the add button","Guard the error-body parse — a non-{error} JSON body makes typia.assert throw its own error inside the catch path","Disable the add control while the POST is in flight"],"tags":["wishlists","validation","http","typia","error-handling"],"backgroundTag":"unprocessable-entity-validation","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}