Skip to content

fix(jellyfin): typed HTTP exception instead of a status code buried in a string - #2819

Closed
PonceGL wants to merge 2 commits into
PixelPlayerHQ:masterfrom
PonceGL:chore/p4-jellyfin-typed-exception
Closed

PonceGL wants to merge 2 commits into
PixelPlayerHQ:masterfrom
PonceGL:chore/p4-jellyfin-typed-exception

Conversation

@PonceGL

@PonceGL PonceGL commented Sep 10, 2026

Copy link
Copy Markdown

What

JellyfinApiService.request() wraps every non-2xx response in
Exception("HTTP $code: ${response.message}"), so callers can't tell 401 from
429 without parsing a message string. This is one of the small independent
fixes listed in #2813.

Changes

  • JellyfinHttpException(statusCode, retryAfter, message) replaces the plain
    Exception on the failure path of request(). retryAfter is passed
    through unparsed (HTTP allows either a number of seconds or an HTTP-date;
    deciding between the two is a caller concern, not this type's).
  • catch (e: CancellationException) { throw e } added before the existing
    catch (e: Exception), which was silently swallowing cancellation.

Why now, and why scoped this tight

Grepped the whole codebase first: nothing parses the old message string, so
this has no other call site to update. authenticateByName() and
checkDownloadPermission() in the same file have the identical
swallowed-cancellation issue, but I left them alone here to keep this PR to
exactly the one thing it claims to do — happy to open a follow-up for those
two if useful.

Testing

5 new JUnit5 tests. No mock-server dependency added — a real
okhttp3.Response built through an Interceptor on the injected client is
enough to exercise request()'s real parsing path (status code, the
Retry-After header, and the happy path), without introducing anything new
to the test graph.

:app:testDebugUnitTest: 393 tests, same 5 pre-existing failures as
master's baseline, none new.

request() envolvía cualquier fallo en Exception("HTTP $code: ..."), enterrando
el código de estado dentro de un String (GEN-AP-06). Sin él, el clasificador de
errores de F3.3 (docs/downloads) no puede distinguir 401/403/404/416/429/5xx sin
parsear texto.

- JellyfinHttpException(statusCode, retryAfter, message): retryAfter va crudo,
  sin parsear — los dos formatos de Retry-After los decide quien clasifica.
- catch (e: CancellationException) { throw e } antes del catch genérico: el
  catch (e: Exception) existente tragaba la cancelación (AND-CONC-04).
- Cero llamantes en el proyecto parseaban el mensaje anterior; sin regresiones.

Self-review (code-review skill, medium effort) surfaced one finding:
authenticateByName(), a few lines below, has the exact same
CancellationException-swallowing catch (e: Exception) — same bug, same file,
just not the method R19 named. Fixed it too, same one-line pattern, with a
test mirroring the existing deterministic cancel-before-call case. Left its
HTTP-failure paths as plain Exception (not JellyfinHttpException): unlike
request(), nothing downstream needs to distinguish auth failure status codes,
and R19/F3.3 don't ask for it there.

6 tests JVM nuevos (5 + 1 de la autorevisión), en verde. Baseline: 393 tests,
los mismos 5 fallos preexistentes de siempre, ninguno nuevo (check-baseline.sh).
@PonceGL

PonceGL commented Sep 10, 2026

Copy link
Copy Markdown
Author

Self-review (code-review, medium effort)

One finding, applied: `authenticateByName()`, a few lines below `request()` in this same file, had the identical `catch (e: Exception)` that swallows `CancellationException` into a `Result.failure` — the exact bug this PR fixes, just not the method R19 named. Fixed with the same one-line pattern, plus a test mirroring the existing deterministic cancel-before-call case.

Left `authenticateByName()`'s HTTP-failure paths as plain `Exception` (not `JellyfinHttpException`) — unlike `request()`, nothing downstream needs to distinguish auth failure status codes, and that's not what R19/F3.3 ask for here.

Re-verified: 6 JVM tests (was 5), all green. Baseline unaffected — 393 tests, same 5 pre-existing failures, none new.

@PonceGL
PonceGL force-pushed the chore/p4-jellyfin-typed-exception branch from f2808bc to 7fa1eed Compare September 10, 2026 11:40
Comments cited local-only planning files and rule IDs (docs/downloads/*.md,
GEN-/AND- rule docs) that don't exist outside this machine and are
meaningless to anyone reviewing the PR. Reworded to keep the same
technical reasoning without the dangling references.
@PonceGL

PonceGL commented Sep 10, 2026

Copy link
Copy Markdown
Author

Closing for now — reorganizing how this work is staged. It'll go through our fork first and we'll propose it upstream again, possibly bundled differently, once the larger feature it's part of is further along. Not a rejection, just a process change on our side.

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.

1 participant