Current state
io/itunes/fetchItunesItems.ts line 95 calls await response.json() without first checking response.ok. When the iTunes Search API returns a non-2xx status (e.g., 429 rate-limit, 500 server error), the response body is an error document that does not conform to { results: [...] }. Calling .json() on it either throws a JSON parse error or, if the body is valid JSON with no results key, silently returns an empty result set. Neither surfaces the underlying HTTP failure clearly. The withRetry wrapper can only retry on thrown errors — it does not see a response-level failure unless .json() happens to throw.
Ideal state
fetchItunesItems checks response.ok after withRetry returns, before calling .json().
- A non-2xx response throws an error that includes the HTTP status code, consistent with how other fetch clients in this codebase handle HTTP failures.
- A 429 or 500 from iTunes appears in build logs as a clear HTTP error, not a downstream JSON parse failure or silent empty list.
Out of scope
Starting points
io/itunes/fetchItunesItems.ts line 95 — the unconditional response.json() call to guard with response.ok
io/tmdb/fetchTmdbList.ts — the existing TMDB client, which has the same gap and serves as a companion reference
QA plan
- Intercept the iTunes API call (via a mock or by temporarily pointing the URL at a server returning 429) and trigger the fetch — expect a thrown error that includes the HTTP status code in its message, not a JSON parse failure.
- With normal iTunes API access, run a full site build — expect unchanged output.
- Run
npx tsc --noEmit — expect no type errors.
Done when
fetchItunesItems checks response.ok before calling .json() and throws an error with the HTTP status when the response is not successful.
Current state
io/itunes/fetchItunesItems.tsline 95 callsawait response.json()without first checkingresponse.ok. When the iTunes Search API returns a non-2xx status (e.g., 429 rate-limit, 500 server error), the response body is an error document that does not conform to{ results: [...] }. Calling.json()on it either throws a JSON parse error or, if the body is valid JSON with noresultskey, silently returns an empty result set. Neither surfaces the underlying HTTP failure clearly. ThewithRetrywrapper can only retry on thrown errors — it does not see a response-level failure unless.json()happens to throw.Ideal state
fetchItunesItemschecksresponse.okafterwithRetryreturns, before calling.json().Out of scope
.json()is called.fetchTmdbListresponse-check gap — tracked separately in issue fetchTmdbList skips response.ok check — HTTP errors silently cache an empty result #132.Starting points
io/itunes/fetchItunesItems.tsline 95 — the unconditionalresponse.json()call to guard withresponse.okio/tmdb/fetchTmdbList.ts— the existing TMDB client, which has the same gap and serves as a companion referenceQA plan
npx tsc --noEmit— expect no type errors.Done when
fetchItunesItemschecksresponse.okbefore calling.json()and throws an error with the HTTP status when the response is not successful.