{"record":{"id":"9b8286b1856615ed","repo":"Hmbown/CodeWhale","slug":"message-app","errorCode":null,"errorMessage":"${message}","messagePattern":"\\$\\{message\\}","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_web/app.mjs","lineNumber":955,"sourceCode":"    }\n    const response = await fetch(path, {\n      ...options,\n      headers,\n      credentials: \"same-origin\",\n      cache: \"no-store\",\n    });\n    if (!response.ok) {\n      let message = `${response.status} ${response.statusText}`.trim();\n      try {\n        const body = await response.json();\n        message = body?.error?.message || body?.message || message;\n      } catch (_error) {\n        // The status line is enough when the response is not JSON.\n      }\n      if (response.status === 401) {\n        message = \"This browser session is not authenticated. Restart `codewhale web` to open a fresh one-time session.\";\n      }\n      throw new Error(message);\n    }\n    if (response.status === 204) return null;\n    const contentType = response.headers.get(\"content-type\") || \"\";\n    return contentType.includes(\"application/json\") ? response.json() : response.text();\n  }\n\n  function renderThreadList() {\n    dom.threadList.replaceChildren();\n    if (app.summaries.length === 0) {\n      const empty = element(\"p\", \"thread-preview\", \"No matching threads\");\n      empty.style.padding = \"8px 10px\";\n      dom.threadList.append(empty);\n      return;\n    }\n\n    const groups = groupThreadSummaries(app.summaries);\n    if (groups.needsYou.length > 0) {\n      appendThreadGroup(\"Needs you\", \"needs-you\", groups.needsYou);","sourceCodeStart":937,"sourceCodeEnd":973,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/runtime_web/app.mjs#L937-L973","documentation":"Generic failure of the browser client's api() wrapper: a fetch to the Runtime web API returned a non-OK HTTP status whose body text (or parsed JSON message) becomes the thrown error message. A 401 is upgraded to a friendly message telling the user their one-time browser session is no longer authenticated.","triggerScenarios":"Any fetch from app.mjs via api() where response.ok is false — e.g. 401 after the one-time session token is consumed/expired, 404 on a stale endpoint, or 500 from a Runtime error.","commonSituations":"Bookmarking the web UI and reopening it later after the one-time session expired; sharing the URL with a second browser; Runtime restarted between page load and an API call; a version-mismatched Runtime missing an endpoint.","solutions":["On the 401 variant, restart `codewhale web` and open the freshly printed one-time session URL in the same browser.","Retry the action after confirming the Runtime process is still running and was not restarted since page load.","If the message shows a 404/500, check Runtime logs for the failing endpoint and align the browser client and Runtime versions."],"exampleFix":"// before: bookmarked stale session URL gets 401\nfetch(\"/v1/providers\")\n// after: always launch via the fresh URL from `codewhale web`\n// $ codewhale web\n// Listening on http://127.0.0.1:PORT/?session=<one-time-token>","handlingStrategy":"try-catch","validationCode":"const res = await fetch('/v1/providers', { headers: authHeaders() });\nif (res.status === 401) throw new Error('session expired — restart codewhale web');\nif (!res.ok) throw new Error(`runtime api ${res.status}`);","typeGuard":"function isAuthError(err) {\n  return err instanceof Error && err.message.includes('not authenticated');\n}","tryCatchPattern":"try {\n  data = await api('/v1/providers');\n} catch (e) {\n  if (isAuthError(e)) showSessionExpiredDialog();\n  else showSnackbar(String(e.message));\n}","preventionTips":["Always open the web UI from the URL printed by the current `codewhale web` run, never bookmarks.","Treat any Runtime restart as invalidating all open browser sessions.","Surface the HTTP status in the UI so users can distinguish auth vs server errors."],"tags":["http","fetch","authentication","browser-client"],"backgroundTag":"http-error-response","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}