{"record":{"id":"a6ee3156ea94b2b3","repo":"antiwork/gumroad","slug":"something-went-wrong-a6ee31","errorCode":null,"errorMessage":"Something went wrong.","messagePattern":"Something went wrong\\.","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/components/Nav.tsx","lineNumber":221,"sourceCode":"  return <section className={classNames(\"mb-4 hidden lg:grid\", { grid: isOpen })}>{children}</section>;\n};\n\nexport const NavLinkDropdownMembershipItem = ({ teamMembership }: { teamMembership: TeamMembership }) => {\n  const onClick = (ev: React.MouseEvent<HTMLAnchorElement>) => {\n    const currentUrl = new URL(window.location.href);\n    // It is difficult to tell if the account to be switched has access to the current page via policies in this context.\n    // Pundit deals with that, and PunditAuthorization concern handles Pundit::NotAuthorizedError.\n    // account_switched param is solely for the purpose of not showing the error message when redirecting to the\n    // dashboard in case the user doesn't have access to the page.\n    currentUrl.searchParams.set(\"account_switched\", \"true\");\n    ev.preventDefault();\n    request({\n      method: \"POST\",\n      accept: \"json\",\n      url: Routes.sellers_switch_path({ team_membership_id: teamMembership.id }),\n    })\n      .then((res) => {\n        if (!res.ok) throw new ResponseError();\n        window.location.href = currentUrl.toString();\n      })\n      .catch((e: unknown) => {\n        assertResponseError(e);\n        showAlert(\"Something went wrong.\", \"error\");\n      });\n  };\n\n  return (\n    <MenuItemRadio checked={teamMembership.is_selected} asChild>\n      <a href={Routes.sellers_switch_path()} onClick={onClick} className=\"min-w-0\">\n        <Avatar src={teamMembership.seller_avatar_url} alt={teamMembership.seller_name} />\n        <span className=\"min-w-0 flex-1 truncate\" title={teamMembership.seller_name}>\n          {teamMembership.seller_name}\n        </span>\n        {teamMembership.is_selected ? <CheckCircle pack=\"filled\" className=\"size-5 h-5 shrink-0 text-accent\" /> : null}\n      </a>\n    </MenuItemRadio>","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/components/Nav.tsx#L203-L239","documentation":"Switching seller accounts from the nav: onClick preventDefaults the link and POSTs to sellers_switch_path(team_membership_id), expecting a redirect back to the current URL with account_switched=true appended (so Pundit-driven redirects to the dashboard do not show an error). A non-ok response throws a bare ResponseError, caught and reported as 'Something went wrong.' — the page does not navigate.","triggerScenarios":"POST sellers_switch_path returning 401 (session expired), 403/404 (team membership revoked or inactive since the nav rendered), or a route change after a deploy — the .then sees !res.ok and throws.","commonSituations":"Membership revoked in another tab/admin while the nav still lists the team; long-lived tab with a dead session; deploy renaming the switch route while cached JS keeps the old URL.","solutions":["Check the Network tab for the sellers_switch POST status: 401 points at the session, 403/404 at the membership.","If 401, reload — a fresh page re-authenticates and re-renders the nav without stale memberships.","If 404 after a deploy, hard-refresh to pick up the new JS bundle with current routes.","Verify the membership still exists and is active in the admin console.","After a successful switch, ensure the redirect keeps the account_switched param so unrelated Pundit denials stay silent."],"exampleFix":"// before\n.then((res) => {\n  if (!res.ok) throw new ResponseError();\n  window.location.href = currentUrl.toString();\n})\n\n// after — a dead session should send the user to re-auth, not show a dead-end alert\n.then((res) => {\n  if (res.status === 401) { window.location.href = Routes.login_path(); return; }\n  if (!res.ok) throw new ResponseError();\n  window.location.href = currentUrl.toString();\n})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const isResponseError = (e: unknown): e is ResponseError => e instanceof ResponseError;","tryCatchPattern":".catch((e: unknown) => {\n  assertResponseError(e);\n  if (needsReauth) { window.location.href = Routes.login_path(); return; } // 401: alert is a dead end\n  showAlert('Something went wrong.', 'error');\n});","preventionTips":["On 401, redirect to login instead of alerting — the user cannot fix a dead session from an alert.","Keep the account_switched=true param on the post-switch URL; without it a Pundit denial shows a spurious error on the target page.","Hard-refresh after deploys if the switch route 404s — cached bundles carry stale route helpers.","Re-fetch the nav/team list on window focus so revoked memberships disappear instead of failing at switch time."],"tags":["http","account-switch","teams","session-expired","navigation"],"backgroundTag":"http-request-failed","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}