{"record":{"id":"109c8c51b81cd073","repo":"odysseus-dev/odysseus","slug":"failed-to-load","errorCode":null,"errorMessage":"Failed to load.","messagePattern":"Failed to load\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"static/js/skills.js","lineNumber":552,"sourceCode":"    return card;\n  });\n}\n\nasync function _expandBuiltinCard(card, name) {\n  const grid = card.closest('.doclib-grid');\n  if (card.classList.contains('doclib-card-expanded')) {\n    card.classList.remove('doclib-card-expanded');\n    return;\n  }\n  if (grid) grid.querySelectorAll('.doclib-card-expanded').forEach(c => c.classList.remove('doclib-card-expanded'));\n  card.classList.add('doclib-card-expanded');\n  if (grid) grid.scrollTop = 0;\n  const pre = card.querySelector('.skill-md-pre');\n  if (pre && !card._loaded) {\n    pre.textContent = 'Loading…';\n    try {\n      const res = await fetch(`${API}/api/skills/builtin/${encodeURIComponent(name)}`);\n      if (!res.ok) throw new Error(`HTTP ${res.status}`);\n      const data = await res.json();\n      pre.textContent = data.text || '(empty)';\n      card._loaded = true;\n      card._text = data.text || '';\n      card._default = data.default || '';\n    } catch (e) {\n      pre.textContent = 'Failed to load.';\n    }\n  }\n}\n\nfunction _toggleBuiltinEdit(card, name) {\n  const preview = card.querySelector('.skill-card-preview');\n  if (!preview) return;\n  if (preview.querySelector('.skill-md-editor')) { _saveBuiltinEdit(card, name); return; }\n  const pre = preview.querySelector('.skill-md-pre');\n  const ta = document.createElement('textarea');\n  ta.className = 'skill-md-editor';","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/skills.js#L534-L570","documentation":"Set as the card's <pre> text in _toggleBuiltinExpand (static/js/skills.js:552) when GET /api/skills/builtin/{name} fails; unlike other handlers the HTTP status is swallowed entirely — the user sees only 'Failed to load.'. The flag card._loaded stays false, so collapsing and re-expanding retries the fetch.","triggerScenarios":"Expanding a built-in skill card in the skills browser: GET /api/skills/builtin/{name}. Fails on 404 (built-in renamed/removed in a server version change), 401 (expired session), or 500 (read error on the packaged builtin file).","commonSituations":"Frontend bundle (static/js) newer or older than the server's built-in skill set after a partial upgrade; auth cookie expired while the page was open; builtin asset missing from a container image.","solutions":["Run the GET by hand (devtools Network tab) to recover the hidden status: 404 → the builtin no longer exists in this server version, reload the page to re-fetch the builtin list; 401 → re-login.","Ensure the frontend and backend are the same version (hard-refresh to bust a stale JS bundle).","Collapse and re-expand the card to retry, since _loaded remains false on failure.","Improve the message to include the status so users can self-diagnose."],"exampleFix":"// before\n} catch (e) {\n  pre.textContent = 'Failed to load.';\n}\n// after\n} catch (e) {\n  pre.textContent = `Failed to load (HTTP ${e.message.replace('HTTP ', '')}). Click to retry.`;\n}","handlingStrategy":"try-catch","validationCode":"if (!name || card._loaded) return; // skip fetch when already loaded or name unknown","typeGuard":null,"tryCatchPattern":"try { const res = await fetch(`${API}/api/skills/builtin/${encodeURIComponent(name)}`); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); pre.textContent = data.text || '(empty)'; card._loaded = true; } catch (e) { pre.textContent = `Failed to load (${e.message}). Collapse and re-expand to retry.`; }","preventionTips":["Put the HTTP status into the failure text — 'Failed to load.' hides the cause.","Leave card._loaded false on failure so re-expand retries.","Keep frontend bundle and server version in sync to avoid unknown builtin names.","Hard-refresh after server upgrades."],"tags":["fetch","api","http","skills","error-visibility"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}