{"record":{"id":"3cf42dbd3f5b54c0","repo":"odysseus-dev/odysseus","slug":"http-res-status-3cf42d","errorCode":null,"errorMessage":"HTTP ${res.status}","messagePattern":"HTTP \\$\\{res\\.status\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/skills.js","lineNumber":590,"sourceCode":"  ta.value = (card._text != null ? card._text : (pre ? pre.textContent : '')) || '';\n  ta.addEventListener('click', (e) => e.stopPropagation());\n  if (pre) pre.style.display = 'none';\n  preview.insertBefore(ta, preview.querySelector('.doclib-card-expanded-actions'));\n  ta.focus();\n  const editBtn = [...preview.querySelectorAll('.doclib-card-action-btn')].find(b => /Edit|Save/.test(b.textContent));\n  if (editBtn) editBtn.innerHTML = '<svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"vertical-align:-1px;margin-right:3px;\"><path d=\"M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z\"/><polyline points=\"17 21 17 13 7 13 7 21\"/><polyline points=\"7 3 7 8 15 8\"/></svg>Save';\n}\n\nasync function _saveBuiltinEdit(card, name) {\n  const ta = card.querySelector('.skill-md-editor');\n  if (!ta) return;\n  try {\n    const res = await fetch(`${API}/api/skills/builtin/${encodeURIComponent(name)}`, {\n      method: 'PUT',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ text: ta.value }),\n    });\n    if (!res.ok) throw new Error(`HTTP ${res.status}`);\n    uiModule.showToast('Built-in capability updated');\n    builtinSkills = [];  // force reload of built-in list (refreshes \"edited\" badge)\n    await loadSkills();\n  } catch (e) { uiModule.showError('Save failed: ' + e.message); }\n}\n\nasync function _revertBuiltin(name) {\n  if (!(await uiModule.styledConfirm(`Revert \"${name}\" to its original built-in instructions?`, { confirmText: 'Revert', danger: true }))) return;\n  try {\n    const res = await fetch(`${API}/api/skills/builtin/${encodeURIComponent(name)}`, { method: 'DELETE' });\n    if (!res.ok) throw new Error(`HTTP ${res.status}`);\n    uiModule.showToast('Reverted to default');\n    builtinSkills = [];\n    await loadSkills();\n  } catch (e) { uiModule.showError('Revert failed: ' + e.message); }\n}\n\nfunction _getFilteredSkills() {","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/skills.js#L572-L608","documentation":"Thrown in _saveBuiltinEdit (static/js/skills.js:590) when PUT /api/skills/builtin/{name} with {text: ta.value} returns non-2xx; surfaced via showError('Save failed: HTTP N'). The route persists an override of a built-in capability's instructions, so failures typically mean the server rejected the write or the builtin no longer exists.","triggerScenarios":"Clicking Save in the built-in skill editor: PUT /api/skills/builtin/{name} with JSON body {text}. 404 when the builtin name is unknown (version skew), 401/403 without rights, 422 when `text` is missing or the wrong type, 500/507 when the override file cannot be written (read-only filesystem, disk full).","commonSituations":"Server container with a read-only volume for skill overrides; frontend bundle from a different release than the server; session expiry during a long editing session; empty textarea still sent as text:'' if the route requires non-empty.","solutions":["Match the HTTP code from the toast: 404 → reload skills (builtin renamed upstream); 422 → check the body shape is exactly {text: string}; 5xx → check write permissions on the overrides directory.","Verify the server process can write to its builtin-overrides storage path.","Re-login on 401 and retry — the textarea content is preserved in the DOM.","After a server upgrade, hard-refresh the app so the builtin list matches the server."],"exampleFix":"// before\nif (!res.ok) throw new Error(`HTTP ${res.status}`);\n// after\nconst d = await res.json().catch(() => ({}));\nif (!res.ok) throw new Error(d.detail || `HTTP ${res.status}`);","handlingStrategy":"try-catch","validationCode":"if (!ta.value.trim()) { uiModule.showError('Text required'); return; }","typeGuard":null,"tryCatchPattern":"try { const res = await fetch(url, { method: 'PUT', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ text: ta.value }) }); const d = await res.json().catch(() => ({})); if (!res.ok) throw new Error(d.detail || `HTTP ${res.status}`); } catch (e) { uiModule.showError('Save failed: ' + e.message); }","preventionTips":["Send {text} exactly; do not invent extra fields the route 422s on.","Check server write permissions on the overrides directory.","Preserve textarea content on failure for retry.","Re-fetch the builtin list after server upgrades before editing."],"tags":["fetch","api","http","skills","filesystem"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}