Finding
Several syndesmos HTTP client methods send a request and discard the response without checking its status. reqwest's send() returns Err only for transport-level failures; HTTP 401, 403, 404, 429, and 5xx all resolve to Ok(Response) and are then dropped, after which the method returns Ok(()). The defect is present in LastfmClient::submit_scrobble and PlexClient::refresh_library_section, and the same .send().await.context(...)?-without-.error_for_status() shape applies to the other request sites (e.g. fetch_favorites).
Evidence
crates/syndesmos/src/lastfm/mod.rs:99-101:
.send()
.await
.context(LastfmApiCallSnafu)?;
crates/syndesmos/src/plex/mod.rs:60:
.send()
.await
.context(PlexApiCallSnafu)?;
In both cases no .error_for_status() (or error_for_status_ref()) call sits between send() and the response being dropped.
Why this matters
Error responses are indistinguishable from success. A 401 from a rotated/expired Last.fm session key or Plex token silently discards every scrobble / library-refresh; a 429 rate-limit is ignored. Because no Err is produced, the circuit breaker never trips, retries never run, and nothing reaches the logs — the integration appears healthy while fully degraded. Silent suppression of remote-rejection state is exactly the failure that hides an interrupted or tampered upstream from the operator.
Desired correction
Insert .error_for_status() (or error_for_status_ref()) after .send().await at each site and map the resulting reqwest::Error through the existing *ApiCallSnafu context — submit_scrobble, refresh_library_section, and fetch_favorites.
Done when: a mock-HTTP test feeding a 401 to submit_scrobble returns Err(LastfmApiCall { .. }) and registers a circuit-breaker failure, and the equivalent test for refresh_library_section returns Err(PlexApiCall { .. }).
Finding
Several syndesmos HTTP client methods send a request and discard the response without checking its status.
reqwest'ssend()returnsErronly for transport-level failures; HTTP 401, 403, 404, 429, and 5xx all resolve toOk(Response)and are then dropped, after which the method returnsOk(()). The defect is present inLastfmClient::submit_scrobbleandPlexClient::refresh_library_section, and the same.send().await.context(...)?-without-.error_for_status()shape applies to the other request sites (e.g.fetch_favorites).Evidence
crates/syndesmos/src/lastfm/mod.rs:99-101:crates/syndesmos/src/plex/mod.rs:60:In both cases no
.error_for_status()(orerror_for_status_ref()) call sits betweensend()and the response being dropped.Why this matters
Error responses are indistinguishable from success. A 401 from a rotated/expired Last.fm session key or Plex token silently discards every scrobble / library-refresh; a 429 rate-limit is ignored. Because no
Erris produced, the circuit breaker never trips, retries never run, and nothing reaches the logs — the integration appears healthy while fully degraded. Silent suppression of remote-rejection state is exactly the failure that hides an interrupted or tampered upstream from the operator.Desired correction
Insert
.error_for_status()(orerror_for_status_ref()) after.send().awaitat each site and map the resultingreqwest::Errorthrough the existing*ApiCallSnafucontext —submit_scrobble,refresh_library_section, andfetch_favorites.Done when: a mock-HTTP test feeding a 401 to
submit_scrobblereturnsErr(LastfmApiCall { .. })and registers a circuit-breaker failure, and the equivalent test forrefresh_library_sectionreturnsErr(PlexApiCall { .. }).