{"record":{"id":"5f97ad5fa38aa7ea","repo":"moeru-ai/airi","slug":"updateuser-failed","errorCode":null,"errorMessage":"updateUser failed","messagePattern":"updateUser failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-pages/src/pages/settings/account/account-settings-page.vue","lineNumber":233,"sourceCode":"}\n\nasync function handleSaveProfile(event: Event) {\n  event.preventDefault()\n  if (profileLoading.value || !profileDirty.value)\n    return\n\n  profileError.value = null\n  profileSuccess.value = null\n  profileLoading.value = true\n\n  const trimmedName = profileForm.name.trim()\n\n  try {\n    const { error } = await authClient.updateUser({\n      name: trimmedName,\n    })\n    if (error)\n      throw new Error(error.message ?? 'updateUser failed')\n\n    if (user.value) {\n      authStore.user = {\n        ...user.value,\n        name: trimmedName,\n      }\n    }\n    profileForm.name = trimmedName\n    profileSuccess.value = t('settings.pages.account.profile.message.saved')\n  }\n  catch (error) {\n    profileError.value = errorMessageFrom(error) ?? t('settings.pages.account.profile.error.fallback')\n  }\n  finally {\n    profileLoading.value = false\n  }\n}\n","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-pages/src/pages/settings/account/account-settings-page.vue#L215-L251","documentation":"The profile-save handler calls better-auth's authClient.updateUser({ name }) and throws when the result carries an error; this literal is only the fallback when better-auth returned an error with no message. The page catches it into profileError with an i18n fallback, so it never escapes as an unhandled rejection.","triggerScenarios":"Expired session so the auth server rejects the update (401); server-side validation rejects the name (empty after trim, too long); auth server unreachable or its baseURL misconfigured relative to SERVER_URL.","commonSituations":"Token expiry after idle; reverse proxy stripping auth cookies; the auth app (server/apps/auth) not running in dev.","solutions":["Log the full error object (status/code) from updateUser before throwing — message alone is often empty.","If 401: sign in again and retry.","Verify the auth client baseURL matches SERVER_URL and cookies are sent.","Validate the trimmed name client-side (non-empty, sane length) before the call."],"exampleFix":"// before\nconst { error } = await authClient.updateUser({ name: trimmedName })\nif (error)\n  throw new Error(error.message ?? 'updateUser failed')\n\n// after\nconst { error } = await authClient.updateUser({ name: trimmedName })\nif (error)\n  throw new Error(error.message ?? `updateUser failed (${error.status ?? 'no status'} ${error.code ?? ''})`)","handlingStrategy":"try-catch","validationCode":"const trimmedName = profileForm.name.trim()\nif (!trimmedName || trimmedName.length > 100) {\n  profileError.value = 'Enter a valid name'\n  return\n}\nif (!authStore.user) {\n  profileError.value = 'Session expired — sign in again'\n  return\n}","typeGuard":null,"tryCatchPattern":"catch (error) {\n  if ((error as { status?: number })?.status === 401)\n    await redirectToSignIn()\n  else\n    profileError.value = errorMessageFrom(error) ?? t('settings.pages.account.profile.error.fallback')\n}","preventionTips":["Check the session before profile mutations.","Preserve error.status/code in the thrown message for diagnosis.","Disable the save button while profileLoading is true to prevent double submits."],"tags":["auth","better-auth","account","profile"],"backgroundTag":"auth-api-error","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}