antiwork/gumroad · error · ResponseError

${response.message}

Error message

${response.message}

What it means

The only throw in this function whose message is the server's own text: refund() received HTTP ok, typia-asserted the body as { success: false; message: string } at line 405, and rethrows ResponseError(response.message). This is the endpoint saying 'valid request, but no refund' — the Charge type declared just above (chargedback, paypal_refund_expired) names the canonical reasons. It never produces 'Something went wrong.' unless the server literally sent that string.

Source

Thrown at app/javascript/data/customers.ts:407

    .then((response) => {
      if (!response.ok) throw new ResponseError();
      return response.json();
    })
    .then((json) => typia.assert<Charge[]>(json));

export const refund = (purchaseId: string, amount: number) =>
  request({
    method: "PUT",
    accept: "json",
    url: Routes.refund_purchase_path(purchaseId, { amount }),
  })
    .then((response) => {
      if (!response.ok) throw new ResponseError();
      return response.json();
    })
    .then((json) => typia.assert<{ success: true } | { success: false; message: string }>(json))
    .then((response) => {
      if (!response.success) throw new ResponseError(response.message);
    });

export const revokeAccess = (purchaseId: string) =>
  request({
    method: "PUT",
    accept: "json",
    url: Routes.revoke_access_purchase_path(purchaseId),
  }).then((response) => {
    if (!response.ok) throw new ResponseError();
  });

export const undoRevokeAccess = (purchaseId: string) =>
  request({
    method: "PUT",
    accept: "json",
    url: Routes.undo_revoke_access_purchase_path(purchaseId),
  }).then((response) => {
    if (!response.ok) throw new ResponseError();

View on GitHub (pinned to afeacbd394)

Solutions

  1. Show e.message verbatim to the operator — it is the server's explanation and is already user-ready
  2. Prevent the attempt: disable the refund action when the loaded Charge has chargedback or paypal_refund_expired set
  3. Re-fetch the purchase/charges immediately before refunding so balance and flags are current
  4. If the message looks wrong or empty, inspect the response body in DevTools — the server controls this string

Example fix

// before
refund(purchase.id, amount);

// after
if (charge.chargedback || charge.paypal_refund_expired) {
  alert('This purchase cannot be refunded here — it was charged back or the PayPal refund window expired.');
  return;
}
try { await refund(purchase.id, amount); }
catch (e) { assertResponseError(e); alert(e.message); }
Defensive patterns

Strategy: try-catch

Validate before calling

const refundBlocked = (charge: Charge) => charge.chargedback || charge.paypal_refund_expired;
if (refundBlocked(charge)) { showBlockedRefundNotice(charge); return; }

Type guard

import typia from 'typia';
const isRefundRefusal = typia.createIs<{ success: false; message: string }>();

Try / catch

try {
  await refund(purchaseId, amount);
  toast('Refunded');
} catch (e) {
  assertResponseError(e);
  toast(e.message); // the server's refusal wording — safe to display verbatim
}

Prevention

When it happens

Trigger: Refunding a charged-back purchase; refunding a PayPal purchase past PayPal's refund window (paypal_refund_expired); the full amount was already refunded or a concurrent refund consumed the balance; the requested amount would over-refund relative to remaining balance.

Common situations: Support attempts a refund after a dispute opened; two tabs refund the same purchase; earlier partial refunds make the requested total impossible; stale UI still offers a Refund button for a purchase the backend already closed out.

Related errors


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