{"record":{"id":"b19fd4cae56f4fd3","repo":"QuantumNous/new-api","slug":"failed-to-update-settings","errorCode":null,"errorMessage":"Failed to update settings","messagePattern":"Failed to update settings","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/features/profile/components/language-preferences-card.tsx","lineNumber":77,"sourceCode":"\n  useEffect(() => {\n    setCurrentLanguage(savedLanguage)\n  }, [savedLanguage])\n\n  const handleLanguageChange = async (language: string | null) => {\n    if (!language) return\n    const nextLanguage = normalizeInterfaceLanguage(language)\n    if (nextLanguage === currentLanguage) return\n\n    const previousLanguage = currentLanguage\n    setCurrentLanguage(nextLanguage)\n    setSaving(true)\n    await i18n.changeLanguage(nextLanguage)\n\n    try {\n      const response = await updateUserLanguage(nextLanguage)\n      if (!response.success) {\n        throw new Error(response.message || t('Failed to update settings'))\n      }\n\n      if (auth.user) {\n        const existingSetting =\n          typeof auth.user.setting === 'string'\n            ? parseUserSettings(auth.user.setting)\n            : (auth.user.setting ?? {})\n        auth.setUser({\n          ...auth.user,\n          setting: JSON.stringify({\n            ...existingSetting,\n            language: nextLanguage,\n          }),\n        })\n      }\n\n      props.onProfileUpdate()\n      toast.success(t('Language preference saved'))","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/QuantumNous/new-api/blob/e2c7aa7b102c2075eae2377df3508658d45e88dc/web/src/features/profile/components/language-preferences-card.tsx#L59-L95","documentation":"Thrown in the language preferences card after switching the UI language: i18n.changeLanguage is applied optimistically, then updateUserLanguage(nextLanguage) persists it; a success=false response throws the backend message or this fallback. The catch path (below the source) rolls the UI language back to previousLanguage.","triggerScenarios":"Selecting a new interface language while the persistence call fails — session expired (401), DB write error on the user settings endpoint, or backend rejects the locale value.","commonSituations":"Long-idle tab where the token expired before saving; backend restarted mid-request; user record locked/updated concurrently; requesting account type that cannot store settings.","solutions":["Refresh and retry — if it was session expiry, re-login makes the save succeed","Verify the chosen locale is in the supported set sent by the backend (en/zh/zh-TW/fr/ru/ja/vi)","Check backend logs for the user-settings update error (DB failures show there)","If it persistently fails for one account, test the same save with another account to isolate user-record issues"],"exampleFix":"// before\nconst response = await updateUserLanguage(nextLanguage)\nif (!response.success) {\n  throw new Error(response.message || t('Failed to update settings'))\n}\n// after - rollback already happens in catch; add one retry for expired-session\nlet response = await updateUserLanguage(nextLanguage)\nif (!response.success && /unauthor|login/i.test(response.message || '')) {\n  response = await updateUserLanguage(nextLanguage) // after silent re-auth\n}\nif (!response.success) {\n  throw new Error(response.message || t('Failed to update settings'))\n}","handlingStrategy":"fallback","validationCode":"const nextLanguage = normalizeInterfaceLanguage(language)\nif (!nextLanguage || nextLanguage === currentLanguage) return\n// verify nextLanguage is in the supported locale list before calling the API","typeGuard":"const isSupportedLocale = (l: string): boolean =>\n  ['en', 'zh', 'zh-TW', 'fr', 'ru', 'ja', 'vi'].includes(l)","tryCatchPattern":"const previousLanguage = currentLanguage\nsetCurrentLanguage(nextLanguage)\ntry {\n  await i18n.changeLanguage(nextLanguage)\n  const response = await updateUserLanguage(nextLanguage)\n  if (!response.success) throw new Error(response.message || t('Failed to update settings'))\n} catch (error) {\n  // rollback the optimistic UI change\n  setCurrentLanguage(previousLanguage)\n  await i18n.changeLanguage(previousLanguage)\n  toast.error(error instanceof Error ? error.message : t('Failed to update settings'))\n} finally {\n  setSaving(false)\n}","preventionTips":["Always pair optimistic language change with a rollback path on save failure","Whitelist locales client-side to avoid backend rejections","Prompt re-login on auth-type failures instead of silently rolling back"],"tags":["api-error","language","settings","optimistic-update","i18n"],"backgroundTag":null,"analyzedSha":"e2c7aa7b102c2075eae2377df3508658d45e88dc","analyzedAt":"2026-08-15T10:35:18.111Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}