{"record":{"id":"c6389fa69a3f239e","repo":"odysseus-dev/odysseus","slug":"detail-http-res-status","errorCode":null,"errorMessage":"detail || ('HTTP ' + res.status)","messagePattern":"detail \\|\\| \\('HTTP ' \\+ res\\.status\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/chatRenderer.js","lineNumber":1255,"sourceCode":"    window.open(reportUrl, '_blank');\n  });\n  wrap.appendChild(btn);\n\n  var chatBtn = document.createElement('button');\n  chatBtn.type = 'button';\n  chatBtn.className = 'view-report-btn chat-about-btn';\n  chatBtn.innerHTML = CHAT_ABOUT_ICON + ' Discuss';\n  chatBtn.addEventListener('click', async function() {\n    if (chatBtn.disabled) return;\n    var origLabel = chatBtn.innerHTML;\n    chatBtn.disabled = true;\n    chatBtn.innerHTML = CHAT_ABOUT_ICON + ' Creating…';\n    try {\n      var res = await fetch(apiBase + '/api/research/spinoff/' + sessionId, { method: 'POST' });\n      if (!res.ok) {\n        var detail = '';\n        try { detail = (await res.json()).detail || ''; } catch {}\n        throw new Error(detail || ('HTTP ' + res.status));\n      }\n      var payload = await res.json();\n      if (window.sessionModule && payload.session_id) {\n        await window.sessionModule.loadSessions().catch(() => {});\n        await window.sessionModule.selectSession(payload.session_id);\n      }\n    } catch (e) {\n      chatBtn.disabled = false;\n      chatBtn.innerHTML = origLabel;\n      if (window.uiModule && uiModule.showError) {\n        uiModule.showError('Could not start follow-up chat: ' + e.message);\n      } else {\n        alert('Could not start follow-up chat: ' + e.message);\n      }\n    }\n  });\n  wrap.appendChild(chatBtn);\n","sourceCodeStart":1237,"sourceCodeEnd":1273,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/chatRenderer.js#L1237-L1273","documentation":"Custom client-side Error thrown by the 'Discuss' button in the chat renderer after POST /api/research/spinoff/{sessionId} returns a non-OK HTTP status. The server's JSON 'detail' field (FastAPI-style error body) is used as the message, falling back to the bare status code. It means the backend refused or failed to create a follow-up chat session for the research report.","triggerScenarios":"POST /api/research/spinoff/{sessionId} responds 4xx/5xx: sessionId no longer exists (404), server error while deriving the spinoff session (500), or an empty 'detail' field in the error body so only 'HTTP <status>' is shown.","commonSituations":"Session was deleted or expired between viewing the report and clicking Discuss; backend restarted and lost in-memory session state; research artifacts missing on disk; auth/session cookie expired.","solutions":["Check the server logs for the actual exception behind the non-OK status of POST /api/research/spinoff/{sessionId}","Verify the sessionId still exists (GET the session list) and reload the page to pick up a fresh id","If the body has no 'detail', reproduce with curl -i -X POST .../api/research/spinoff/<id> to see the raw status and body","Handle 404 specifically by informing the user the report session is gone and offering a reload"],"exampleFix":"// before\nvar detail = '';\ntry { detail = (await res.json()).detail || ''; } catch {}\nthrow new Error(detail || ('HTTP ' + res.status));\n\n// after\nvar detail = '';\ntry { detail = (await res.json()).detail || ''; } catch {}\nif (res.status === 404) throw new Error('Report session no longer exists — reload the page');\nthrow new Error(detail || ('HTTP ' + res.status + ' ' + res.statusText));","handlingStrategy":"try-catch","validationCode":"if (!sessionId) { uiModule.showError('No report session loaded'); return; }","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetch(apiBase + '/api/research/spinoff/' + encodeURIComponent(sessionId), { method: 'POST' });\n  if (!res.ok) {\n    const detail = await res.json().then(d => d.detail).catch(() => '');\n    if (res.status === 404) throw new Error('Report session no longer exists — reload');\n    throw new Error(detail || `HTTP ${res.status} ${res.statusText}`);\n  }\n  const payload = await res.json();\n  if (window.sessionModule && payload.session_id) {\n    await window.sessionModule.loadSessions().catch(() => {});\n    await window.sessionModule.selectSession(payload.session_id);\n  }\n} catch (e) {\n  chatBtn.disabled = false;\n  chatBtn.innerHTML = origLabel;\n  (window.uiModule?.showError || console.error)('Could not start follow-up chat: ' + e.message);\n}","preventionTips":["URL-encode sessionId in the path to avoid malformed-route 404s","Disable the button only during flight and always restore it in finally-style cleanup","Treat 404 as stale session and prompt a reload instead of a generic error"],"tags":["fetch","http-error","session","frontend"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}