/search renders the SearchError "Search is temporarily unavailable — we're having trouble connecting to our search service, this is on our end, not yours" page whenever the DPLA API returns a 4xx, not only on real outages. A bad query isn't an outage — search is up — so the copy is wrong and blames us for a request that was simply invalid.
Repro
/search with a collection (or q) value longer than 200 chars → API returns 400 {"message":"… must be between 2 and 200 characters"} → outage page.
- Real example that surfaced it:
q="lgbtq archive" with a ~600-char collection facet value (a citation string that had been indexed as a collection title).
- Backend healthy throughout (CB 0, API 5xx 0) — only this request 400s.
Cause — pages/search/index.js, ES path:
if (isUpstreamUnavailable(res)) { // 5xx / network → 503 degrade (correct)
return fetchErrorProps(await markUpstreamUnavailable(context.res, res));
}
if (!res.ok) { // 4xx
context.res.statusCode = res.status; // status kept as 400 — good
return fetchErrorProps(); // but same props → same <SearchError/> as the outage path
}
Status is handled right (stays 400), but both branches return fetchErrorProps() (fetchError: true → <SearchError/>), so 4xx and 5xx render identical "service is down" UI.
Expected
- A 4xx should render a distinct "that search isn't valid" state (or drop the offending param and re-run), not the outage/"on our end" copy.
- Precedent already in this file: the
page > MAX_PAGE_SIZE branch returns a separate maxPageError state instead of SearchError — same idea for an API 4xx.
Scope: frontend UI classification only. How over-length values get indexed/faceted in the first place is a separate ingestion/API concern, tracked elsewhere.
Rides on #1577 (degrade-to-503 feature).
/searchrenders theSearchError"Search is temporarily unavailable — we're having trouble connecting to our search service, this is on our end, not yours" page whenever the DPLA API returns a 4xx, not only on real outages. A bad query isn't an outage — search is up — so the copy is wrong and blames us for a request that was simply invalid.Repro
/searchwith acollection(orq) value longer than 200 chars → API returns400 {"message":"… must be between 2 and 200 characters"}→ outage page.q="lgbtq archive"with a ~600-charcollectionfacet value (a citation string that had been indexed as a collection title).Cause —
pages/search/index.js, ES path:Status is handled right (stays 400), but both branches return
fetchErrorProps()(fetchError: true→<SearchError/>), so 4xx and 5xx render identical "service is down" UI.Expected
page > MAX_PAGE_SIZEbranch returns a separatemaxPageErrorstate instead ofSearchError— same idea for an API 4xx.Scope: frontend UI classification only. How over-length values get indexed/faceted in the first place is a separate ingestion/API concern, tracked elsewhere.
Rides on #1577 (degrade-to-503 feature).