> STATUS: RESOLVED (as of build e6c937427256, 2026-06-07). The JS-syntax/script-block fragmentation issue described below no longer applies. The dashboard template was extracted from web.py into assets/dashboard.html (13,633 lines as of this build); all chat JS functions (loadChat, sendChat, groveFetch, loadChatConversations, switchTab) are present and at stable line numbers in that file (loadChat ~3570, sendChat ~12653, groveFetch ~12528, loadChatConversations ~12841). The multi-script-block layout referenced below (blocks at lines 8384, 10944, 11504 of web.py) no longer exists. The window.onerror title handler is retained at dashboard.html ~1544. This file is retained as a historical incident record.
On the cell dashboard chat tab:
1. Selecting a peer from the dropdown shows "Loading chat..." forever โ messages never render
2. The expandable "Conversations" list also shows "Loading..." and never populates
3. No requests for /api/chat or /api/chat/conversations appear in server logs at all
Chat was working earlier in the session. The issue appeared after a series of UI changes were made to the chat tab:
<details> with ontoggle/onclick)No HTTP requests reach the server. The Flask logs show zero hits to /api/chat or /api/chat/conversations. This means the JS is failing silently before making the fetch call. A hard refresh (Cmd+Shift+R) does not fix it, ruling out simple caching.
The cell dashboard has multiple <script> blocks. An error in one block can prevent later blocks from executing. Key script blocks and their line ranges:
<script> at line 8384 โ contains loadChat(), switchTab(), closes at line 9482<script> at line 10944 โ chat form isolated handler, closes at line 11015<script> at line 11100 โ GroveAI JS, closes at line 11500<script> at line 11504 โ contains groveFetch(), sendChat(), loadChatConversations(), closes at line 12641If the script block at 11504 has a syntax error, groveFetch won't be defined, and loadChat (which calls groveFetch at line 9428) will throw a ReferenceError when invoked.
Jinja2 template variables inside JS strings could produce invalid JS. For example, an unescaped ' in a peer name or config value could break a string literal and kill the entire script block.
loadChatConversations or nearby code has a syntax issueThe function was added at line ~12389. Even though brace counting shows balanced {}s, there could be other syntax issues (unclosed template literals, bad escaping, etc.).
Python script checked all script blocks containing the chat code. Both blocks (8384-9482 and 11504-12641) have perfectly balanced { and } counts. So it's not a missing brace.
The Flask server is running and responding to other API calls (/api/version, /api/health, /api/pubkey all return 200). The issue is purely client-side โ JS fails before making any fetch.
Cmd+Shift+R was tried โ same result. Rules out stale cached JS. The rendered HTML from the server has the broken code.
window.onerror handler existsLine 8359 has: window.onerror=function(m,s,l,c,e){document.title='ERR L'+l+' C'+c+': '+m;} โ if a JS error occurs, the page title should change to show the error line/column. Check the browser tab title for ERR L... text.
These are all the chat-related edits made before the break occurred, in order. The bug was introduced somewhere in this sequence:
1. Sync globals + timestamp tracking โ Added _last_sync_time, _last_sync_ok globals, updated opp_sync_loop and manual sync to record timestamps. (Backend only, unlikely cause.)
2. /api/network-health endpoint โ New API endpoint returning My Data / My Cell / sync status. (Backend only.)
3. Network Health HTML revamp โ Replaced old health section with new My Data / My Cell / last sync layout, moved Sync Now and Prune buttons. (HTML only, in dashboard template but outside chat tab.)
4. loadStorageBreakdown JS rewrite โ Changed from fetching /api/replication-summary to /api/network-health. This is in the script block at 11504-12641 โ same block as groveFetch, sendChat, and loadChatConversations. A syntax error here would kill the entire block.
5. _last_sync_time / _last_sync_ok in manual sync โ Backend only.
6. /api/exchange-secret auth relaxation โ Backend only.
7. Chat queue + retry (_retry_undelivered_chat) โ Backend only.
8. send_message refactor โ Changed pubkey resolution to try config first (offline support), added encryption pubkey caching, changed response to return queued: true. Backend + response format change.
9. sendChat JS rewrite โ Added "sending..." indicator, disabled button during send, swapped from inline message append to a two-phase approach (show sending div, then replace with final). This is in script block 11504-12641. Template literal changes here could have syntax issues.
10. loadChat changes โ Added container.innerHTML = 'Loading chat...' at the top, and added GroveAI immediate UI render. This is in script block 8384-9482. If this block has an error, loadChat itself won't be defined.
11. Duplicate handler removal โ Removed onclick and onkeydown inline attributes from chat input/button. (HTML only.)
12. Conversations list โ Added <details> HTML, /api/chat/conversations endpoint, loadChatConversations JS function, selectConversation JS function. JS in script block 11504-12641.
13. switchTab modification โ Added if (tab === 'chat') setTimeout(...) call to loadChatConversations. This is in script block 8384-9482.
14. Prune button label / alignment changes โ HTML + JS in different script block (prune is in 8384-9482 area). The checkPruneStatus JS change modified button text โ low risk but in the same script block as loadChat.
If window.onerror fired, the tab title will show something like ERR L12345 C67: Unexpected token. This gives exact line and column of the error.
Open dev tools (Cmd+Option+I on Mac, or right-click โ Inspect โ Console). Look for red errors:
ReferenceError: groveFetch is not defined โ script block 11504-12641 failed to executeSyntaxError: Unexpected token โ bad JS syntax, line number will pinpoint itTypeError: ... is not a function โ function exists but something it calls doesn'tIn browser console, type:
typeof groveFetch // 'function' if script block 11504 is OK
typeof loadChat // 'function' if script block 8384 is OK
typeof sendChat // 'function' if script block 11504 is OK
typeof loadChatConversations // 'function' if conversations code is OK
typeof switchTab // 'function' if script block 8384 is OK
If any returns 'undefined', that script block is broken.
Open these URLs in the browser (must be logged into dashboard):
http://localhost:5678/api/chat/conversations
http://localhost:5678/api/chat?peer=100.126.143.83
If they return JSON, the backend is fine and the problem is purely JS.
Since we know chat was working before these changes and the most likely culprit is a JS syntax error in one of the script blocks:
Option A โ Remove conversations code:
Delete the loadChatConversations function, selectConversation function, the <details> HTML, and the switchTab chat hook. If chat loading recovers, the conversations code has a syntax error.
Option B โ Check the sendChat rewrite:
The sendChat function was heavily rewritten with template literals containing ${} interpolation. Jinja2 also uses ${} is not a conflict, but {{ }} IS โ if any Jinja variable accidentally appears inside a JS template literal in this block, it would cause a syntax error. Search for {{ inside the script block at lines 11504-12641.
Option C โ Render the dashboard HTML and search for syntax errors:
# Save the rendered dashboard HTML
curl -s -b <session-cookie> http://localhost:5678/dashboard > /tmp/dashboard.html
# Extract the suspect script block and lint it
# Or just search for obvious issues
grep -n 'SyntaxError\|undefined\|NaN' /tmp/dashboard.html
If debugging is taking too long, revert web.py to the last known-good commit (before chat changes) using:
git stash # save current changes
git log --oneline -10 # find the good commit
git checkout <hash> -- web.py # restore just web.py
Then re-apply changes one at a time to find which one breaks chat.
| Function | Line | Script Block | Purpose |
|---|---|---|---|
switchTab() |
~8405 | 8384-9482 | Tab switching, triggers chat load |
loadChat() |
~9392 | 8384-9482 | Loads chat for selected peer |
checkPruneStatus() |
~8753 | 8384-9482 | Updates prune button text |
fallbackSend() |
~10971 | 10944-11015 | Isolated chat form handler |
groveFetch() |
~12103 | 11504-12641 | Auth-aware fetch wrapper |
sendChat() |
~12211 | 11504-12641 | Primary chat send function |
loadChatConversations() |
~12389 | 11504-12641 | Conversations list loader |
loadStorageBreakdown() |
~12105 | 11504-12641 | Network health data loader |
/api/chat |
~19876 | โ | Chat messages endpoint |
/api/chat/conversations |
~19914 | โ | Conversations list endpoint |
window.onerror handler at line 8359 should surface errors in the page title โ check this firstsendChat rewrite (item 9) because it uses JS template literals heavily, and template literals inside Jinja2 templates are a known source of escaping issuesloadChatConversations (item 12) since it was entirely new code added to the critical script block