1 Commits
Author SHA1 Message Date
MarekWoandClaude Opus 5 59ef0dd6be fix(ui): explain a non-JSON answer instead of printing its parse error
An instance published behind an access list or Cloudflare Zero Trust gets
an HTML login or error page in place of JSON once that session expires.
`resp.json()` then throws "Unexpected token '<', "<!DOCTYPE "...", and the
repeater panes printed that at the user. Diagnosed on the production
server 2026-09-08: the origin had answered a clean 504 JSON ("No reply
from repeater within 10s") and nginx passed it through untouched, so the
HTML could only have come from in front of it.

New window.fetchJson() (fetch-utils.js, loaded from _head_i18n.html so all
eight entry points get it) returns the parsed body — `data.success` and
`data.error` checks are unchanged — and reports anything else in the same
shape the API uses: {success:false, error, http_status, non_json|offline}.
A 401/403 with a non-JSON body is named as an expired login, since that is
the case the user can act on; an error the API sent as JSON keeps its own
message. 88 call sites converted; those that deliberately inspect the
response (resp.ok/status, blob, uploads) still use fetch directly.

Also stops three catch blocks in the repeater panes from rendering the raw
exception text.

Verified in a browser: normal calls unchanged, an HTML answer comes back
as a readable sentence, a refused connection as a network error, and all
seven pages load with no console errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 11:47:31 +02:00