{"record":{"id":"b53692c7464bb8a0","repo":"odysseus-dev/odysseus","slug":"failed-to-save","errorCode":null,"errorMessage":"Failed to save","messagePattern":"Failed to save","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/settings.js","lineNumber":717,"sourceCode":"    const settings = await settingsRes.json();\n    if (settings.image_model) modelSel.value = settings.image_model;\n    if (settings.image_quality) qualSel.value = settings.image_quality;\n    if (enabledToggle) enabledToggle.checked = settings.image_gen_enabled === true;\n  } catch (e) { console.warn('Failed to load settings', e); }\n\n  function syncImgDisabled() {\n    var off = enabledToggle && !enabledToggle.checked;\n    var card = enabledToggle ? enabledToggle.closest('.admin-card') : null;\n    if (card) card.style.opacity = off ? '0.45' : '';\n    if (configWrap) configWrap.style.pointerEvents = off ? 'none' : '';\n  }\n  syncImgDisabled();\n\n  async function saveSettings() {\n    try {\n      const res = await fetch('/api/auth/settings', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({ image_gen_enabled: enabledToggle ? enabledToggle.checked : false, image_model: modelSel.value, image_quality: qualSel.value }) });\n      if (!res.ok) throw new Error(await res.text().catch(() => `HTTP ${res.status}`));\n      msg.textContent = 'Saved'; msg.style.color = 'var(--fg)'; setTimeout(() => { msg.textContent = ''; }, 2000);\n    } catch (e) { msg.textContent = 'Failed to save'; msg.style.color = 'var(--red)'; }\n  }\n  modelSel.addEventListener('change', saveSettings);\n  qualSel.addEventListener('change', saveSettings);\n  if (enabledToggle) enabledToggle.addEventListener('change', function() { syncImgDisabled(); saveSettings(); });\n}\n\n/* ── Vision ── */\nasync function initVisionSettings() {\n  const vlSel = el('set-vlModelSelect');\n  const msg = el('set-visionSettingsMsg');\n  const enabledToggle = el('set-visionEnabledToggle');\n  const configWrap = vlSel ? vlSel.closest('div[style*=\"flex-direction\"]') : null;\n  var _visionEndpoints = [];\n  var visionFallbackWidget = null;\n  var _vlExclude = ['audio', 'realtime', 'tts', 'dall-e', 'embedding', 'search', 'whisper'];\n  function _isVisionModel(mid) {","sourceCodeStart":699,"sourceCodeEnd":735,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/settings.js#L699-L735","documentation":"Inline settings message shown when saving image-generation settings fails. saveSettings POSTs {image_gen_enabled, image_model, image_quality} to /api/auth/settings; non-OK throws with the response text (or 'HTTP <status>'), and the catch flattens everything to 'Failed to save'.","triggerScenarios":"POST /api/auth/settings returns 4xx (unauthenticated, admin-only endpoint, invalid model/quality value) or 5xx; network failure; auto-save fires on 'change' events while a previous save is in flight.","commonSituations":"Non-admin user opening the settings pane; auth cookie expired so the save silently 401s; choosing a model the backend rejects; rapid consecutive changes racing each other.","solutions":["Check devtools for the POST /api/auth/settings status and body","Re-login / confirm the account has permission to change auth settings","Verify model and quality values are ones the backend accepts","Debounce the change-driven autosave and surface e.message instead of a fixed string"],"exampleFix":"// before\n    } catch (e) { msg.textContent = 'Failed to save'; msg.style.color = 'var(--red)'; }\n\n// after\n    } catch (e) {\n      console.error('image settings save failed:', e);\n      msg.textContent = 'Failed to save: ' + e.message;\n      msg.style.color = 'var(--red)';\n    }","handlingStrategy":"try-catch","validationCode":"if (!navigator.onLine) { msg.textContent = 'Offline'; return; }\nif (!modelSel.value || !qualSel.value) { msg.textContent = 'Select model and quality'; return; }","typeGuard":null,"tryCatchPattern":"try { const res = await fetch(...); if (!res.ok) throw new Error(await res.text().catch(() => `HTTP ${res.status}`)); ... } catch (e) { msg.textContent = 'Failed to save: ' + e.message; }","preventionTips":["Debounce the change-driven autosave so requests don't race","Confirm the account may call /api/auth/settings","Surface e.message — the current fixed string hides auth failures","Disable inputs while a save is pending"],"tags":["network","fetch","settings","autosave","auth"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}