Every attempt to see Emby's actual error message by hand failed the same
way: hls.js's own error reporting only ever exposes the generic HTTP
reason phrase, never the real response body, and Emby's own live log
view didn't reliably surface the exception's headline message either -
across several different items and failure modes this session. Emby's
own access log confirmed a real, several-KB text body really was being
sent every time (Content-Type: text/plain, Content-Length: 5190) - it
just never survived being reported back through either of those paths.
Fixed at the root: EmbyClient.fetch - the one function every Emby call in
this app goes through (fetchJson's JSON API calls and proxyResponse's
streaming/image proxy alike) - now logs Emby's status and full response
body itself straight to docker logs whenever a call fails.
- server/src/emby/EmbyClient.ts: new private logErrorResponse, called
from fetch() only when !res.ok. Reads the body via .clone() so the real
caller still gets an untouched, fully readable response (a body can
only be consumed once, and this had to not break either of the two very
different ways this app's callers read one - fetchJson's .json(),
proxyResponse's .text()/pipe). pathAndQuery is logged with api_key
redacted - this can be called with Emby's own TranscodingUrl verbatim,
which can carry one (same concern as CatalogService's logStreamRequest).
- server/src/Logger.ts: new emby() method, same shape as party()/stream().
- server/test/embyClient.test.ts (new): body/status logged and readable
by the real caller afterward, api_key redaction, and silence on a
successful response (only failures are worth logging, same discipline
as this app's existing logging).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>