{"record":{"id":"c7f5a92440eb5bcc","repo":"antiwork/gumroad","slug":"sorry-something-went-wrong-please-try-again-c7f5a9","errorCode":null,"errorMessage":"Sorry, something went wrong. Please try again.","messagePattern":"Sorry, something went wrong\\. Please try again\\.","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/components/Settings/PasswordPage/PasskeysSection.tsx","lineNumber":71,"sourceCode":"    const nickname = editingNickname.trim();\n    if (!nickname || nickname === passkey.nickname) {\n      setEditingId(null);\n      return;\n    }\n\n    setSavingRename(true);\n    try {\n      const response = await request({\n        url: Routes.settings_passkey_path(passkey.id),\n        method: \"PATCH\",\n        accept: \"json\",\n        data: { nickname },\n      });\n      const result = typia.assert<{ success: boolean; passkey?: Passkey; error_message?: string }>(\n        await response.json(),\n      );\n      if (!response.ok || !result.success || !result.passkey) {\n        throw new ResponseError(result.error_message ?? GENERIC_ERROR);\n      }\n\n      const updated = result.passkey;\n      setPasskeys((current) => current.map((item) => (item.id === updated.id ? updated : item)));\n      setEditingId(null);\n    } catch (e) {\n      showAlert(e instanceof ResponseError ? e.message : GENERIC_ERROR, \"error\");\n    } finally {\n      setSavingRename(false);\n    }\n  });\n\n  const handleConfirmDelete = asyncVoid(async () => {\n    if (!pendingDeletion) return;\n\n    setDeleting(true);\n    try {\n      const response = await request({","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/components/Settings/PasswordPage/PasskeysSection.tsx#L53-L89","documentation":"Generic fallback shown when renaming a passkey in Gumroad's settings fails. handleRename PATCHes Routes.settings_passkey_path(passkey.id) with { nickname } and typia-asserts the JSON body; it throws ResponseError with the server's error_message when !response.ok, success is false, or the updated passkey object is missing. The literal 'Sorry, something went wrong. Please try again.' (GENERIC_ERROR) appears only when the server sent no error_message — or when the body failed the typia.assert shape check (e.g. an HTML error/redirect page), since the catch substitutes GENERIC_ERROR for any non-ResponseError exception.","triggerScenarios":"PATCH /settings/passkeys/:id returns 401/419/422/500 without an error_message key; the session expired so the response is a login redirect (HTML) and typia.assert throws instead; controller-side nickname validation fails; or success:true comes back without the passkey object.","commonSituations":"Settings tab left open past session expiry (Rails authenticity token now invalid, 422 CSRF), the passkey deleted in another tab so the id no longer exists, a deployed API change renaming fields and breaking the typia contract, or a server 500 with an empty JSON body.","solutions":["Reload the settings page and retry — this refreshes the session and CSRF token.","Confirm the passkey still appears in the list; if it vanished, it was deleted elsewhere and the rename target no longer exists.","Inspect the PATCH response in the network tab: an HTML body means the request was redirected to login rather than a rename failure.","If you control the endpoint, always return { success: false, error_message: '...' } on failure so users see the real reason instead of GENERIC_ERROR."],"exampleFix":"# Rails controller, before\nrender json: { success: false }, status: :unprocessable_entity\n# after — client shows the real reason instead of GENERIC_ERROR\nrender json: { success: false, error_message: \"Nickname can't be blank.\" }, status: :unprocessable_entity","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const isPasskeyMutationFailure = (\n  response: Response,\n  result: { success?: boolean; passkey?: Passkey | null },\n): boolean => !response.ok || result.success !== true || result.passkey == null;","tryCatchPattern":"try {\n  const response = await request({ url: Routes.settings_passkey_path(passkey.id), method: \"PATCH\", accept: \"json\", data: { nickname } });\n  const result = typia.assert<{ success: boolean; passkey?: Passkey; error_message?: string }>(await response.json());\n  if (!response.ok || !result.success || !result.passkey) {\n    throw new ResponseError(result.error_message ?? GENERIC_ERROR);\n  }\n} catch (e) {\n  showAlert(e instanceof ResponseError ? e.message : GENERIC_ERROR, \"error\");\n} finally {\n  setSavingRename(false);\n}","preventionTips":["Always return error_message in JSON failure responses so the fallback never fires.","Keep the typia-asserted response shape under contract tests to catch API drift early.","Redirect to login on 401/HTML bodies instead of surfacing a generic error."],"tags":["passkeys","webauthn","settings","http","json-api","typia"],"backgroundTag":"http-request-failed","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}