antiwork/gumroad · error · ResponseError

Request failed (${response.status})

Error message

Request failed (${response.status})

What it means

Load-path error in the Stripe payouts 'beneficial owners' KYC section. The refresh() callback GETs Routes.settings_beneficial_owners_path expecting { beneficial_owners: [...] }; any non-2xx status throws ResponseError(`Request failed (${response.status})`) — a template literal, so the user sees the real status interpolated (e.g. 'Request failed (401)'). Network failures and JSON/typia mismatches instead produce 'Couldn't load beneficial owners.', so this exact message pinpoints an HTTP status problem rather than a parsing or transport one.

Source

Thrown at app/javascript/components/Settings/PaymentsPage/BeneficialOwnersSection.tsx:458

    if (formError) formErrorRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
  }, [formError]);
  const [isSaving, setIsSaving] = React.useState(false);
  const [pendingDeletion, setPendingDeletion] = React.useState<BeneficialOwner | null>(null);
  const [isDeleting, setIsDeleting] = React.useState(false);
  const [isEditingTaxId, setIsEditingTaxId] = React.useState(false);
  const [useGovernmentIdForUs, setUseGovernmentIdForUs] = React.useState(false);
  const uid = React.useId();

  const refresh = React.useCallback(async () => {
    setIsLoading(true);
    setLoadError(null);
    try {
      const response = await request({
        method: "GET",
        url: Routes.settings_beneficial_owners_path(),
        accept: "json",
      });
      if (!response.ok) throw new ResponseError(`Request failed (${response.status})`);
      const data = typia.assert<{ beneficial_owners: BeneficialOwner[] }>(await response.json());
      setOwners(data.beneficial_owners);
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : "Couldn't load beneficial owners.");
    } finally {
      setIsLoading(false);
    }
  }, []);

  React.useEffect(() => {
    void refresh();
  }, [refresh]);

  const openCreate = () => {
    setEditState({ mode: "create" });
    setFormState(blankFormState(defaultCountry));
    setFormError(null);
    setIsEditingTaxId(true);

View on GitHub (pinned to afeacbd394)

Solutions

  1. Read the status from the message itself — it is the response's actual HTTP code.
  2. For 401/redirect: reload, re-authenticate, then reopen the Payments page section.
  3. For 403: verify the account is eligible for the Stripe payouts KYC flow.
  4. For 5xx: check Rails logs for the raised exception in the beneficial owners controller.
Defensive patterns

Strategy: try-catch

Type guard

const isNonOkJson = async (
  response: Response,
): Promise<{ ok: true } | { ok: false; status: number; body: unknown }> =>
  response.ok ? { ok: true } : { ok: false, status: response.status, body: await response.json().catch(() => null) };

Try / catch

try {
  const response = await request({ method: "GET", url: Routes.settings_beneficial_owners_path(), accept: "json" });
  if (!response.ok) throw new ResponseError(`Request failed (${response.status})`);
  const data = typia.assert<{ beneficial_owners: BeneficialOwner[] }>(await response.json());
  setOwners(data.beneficial_owners);
} catch (error) {
  setLoadError(error instanceof Error ? error.message : "Couldn't load beneficial owners.");
} finally {
  setIsLoading(false);
}

Prevention

When it happens

Trigger: GET /settings/beneficial_owners returns 401 (expired session), 403 (account not eligible for the payouts KYC flow), 404/419, or 500 — anything that makes response.ok false after the request completed.

Common situations: Session expiry while the payments page sat open, staging deploys where the route is missing, seller accounts that cannot access payouts KYC endpoints, or server-side exceptions in the beneficial owners controller.

Related errors


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