Skip to content

fix(stream): map upstream Subsonic error envelopes to HTTP errors - #286

Merged
benders merged 1 commit into
mainfrom
feature/285-stream-error-envelope
Sep 14, 2026
Merged

benders merged 1 commit into
mainfrom
feature/285-stream-error-envelope

Conversation

@benders

@benders benders commented Sep 14, 2026

Copy link
Copy Markdown
Owner

Closes #285

Problem

Navidrome answers a stale or missing track ID on /rest/stream with HTTP 200 and <error code="70"/>. The hub sent that XML to clients as a successful audio response and logged the transfer as a success.

Fix

  • hub/src/routes/upstream-envelope.ts (new): detects a Subsonic error envelope by content-type (application/xml, text/xml, application/json) and reads it, capped at 64 KB. Code 70 maps to 404, anything else to 502. It never echoes upstream text back to the client.
  • /rest/stream: checks for an envelope before writing headers and records the failure in stream_operations. Non-2xx peer responses now map to 404 or 502 and are logged as failures too; 416 still passes through.
  • /rest/download: same check for single tracks. Album ZIPs skip the broken entry instead of saving XML as an audio file.
  • /federation/stream/:id: returns 404/502 JSON instead of relaying the envelope, and records no kind='proxy' row.
  • FEDERATION_API_VERSION 7 → 8. Works with older hubs in both directions: a v8 caller still recognizes an envelope relayed by a v5–v7 peer, and a pre-v8 caller gets a real HTTP error. The minimum version stays at 5.
  • Docs: federation-api.md endpoint row and changelog; new row in pitfalls.md.

Tests

  • stream.test.ts:
    • local XML code 70 → 404, with a failure row and no XML in the body
    • JSON code 0 → 502
    • download → 404
    • peer path → 404 on the calling hub, with no proxy row on the source hub
  • upstream-envelope.test.ts: unit tests for content-type detection, parsing and reading.
  • pnpm verify passes with no lint output. pnpm test:federation passes (84 compat tests plus all federation assertions).

Follow-up

🤖 Generated with Claude Code

https://claude.ai/code/session_01CNTqdCoTsmaZ6cqH1x5VRn

Navidrome answers a stale/missing track ID on /rest/stream with HTTP 200
+ <error code="70"/>. The hub relayed that as a 200 audio response and
logged a successful transfer.

- routes/upstream-envelope.ts: detect envelope by content-type, parse
  code; 70 -> 404, anything else -> 502. Never echoes upstream text.
- /rest/stream: reject envelopes and non-2xx peer responses (416 still
  passes through) before writing headers; record the failure in
  stream_operations.
- /rest/download: same check for single tracks; album ZIPs skip the
  entry instead of writing XML as audio.
- /federation/stream/:id: return 404/502 instead of relaying the
  envelope, no kind='proxy' row. FEDERATION_API_VERSION 7 -> 8
  (backward-compatible both ways; floor unchanged).

closes #285

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CNTqdCoTsmaZ6cqH1x5VRn
@benders
benders marked this pull request as ready for review September 14, 2026 17:10
@benders
benders merged commit b60625a into main Sep 14, 2026
1 of 2 checks passed
@benders
benders deleted the feature/285-stream-error-envelope branch September 14, 2026 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(stream): upstream Subsonic error envelope relayed as a 200 audio response

1 participant