fix(frontend): don't retry project README fetch on 404/403#578
Conversation
Closes calkit#572. `useProjectReadme` relied on React Query's default retry policy (3 attempts), so fetching `README.md` from a project that has none burned four round-trips before settling on "no README". A missing README is the common case for fresh projects, so the retries are pure latency with no chance of success. Adopts the same retry policy already used by `useProject` above it (lines 16-21): drop retries on "Not Found" and "Forbidden", otherwise fall back to up to three attempts for transient errors. Pattern is already in the codebase, so this keeps the retry behaviour consistent across the two hooks.
There was a problem hiding this comment.
Pull request overview
This PR updates the frontend’s useProjectReadme hook to avoid React Query retries when a project’s README.md fetch fails with expected 404/403 responses, reducing unnecessary latency for new projects without a README.
Changes:
- Add a React Query
retrypredicate touseProjectReadmeto stop retrying on “Not Found” / “Forbidden”. - Add an inline comment explaining why missing READMEs are expected and shouldn’t trigger retries.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| retry: (failureCount, error) => { | ||
| // A missing README is the common case for fresh projects — don't | ||
| // burn three extra round-trips before the UI settles on "no README". | ||
| if (error.message === "Not Found" || error.message === "Forbidden") { | ||
| return false | ||
| } | ||
| return failureCount < 3 |
There was a problem hiding this comment.
The retry predicate relies on matching error.message strings ("Not Found"/"Forbidden"). Since ProjectsService errors are ApiError with a stable numeric status, it would be more robust to branch on error.status === 404/403 (or to derive status with optional chaining) rather than on the message text. This also mirrors the status-based checks used elsewhere in the frontend and avoids breakage if the error mapping/message ever changes.
Closes #572.
Summary
useProjectReadme(infrontend/src/hooks/useProject.ts) used React Query's default retry policy, so fetchingREADME.mdfrom a project that has none caused 4 round-trips before the UI settled on "no README". A missing README is the common case for fresh projects, so the retries were pure latency with zero chance of succeeding.Change
Adds the same
retrypredicate already used byuseProjecta few lines above — drop onNot Found/Forbidden, otherwise retry up to 3 times:Plus a short comment explaining why missing README is the expected case.
Verification
tsc --noEmitclean (no new diagnostics inuseProject.tsor anywhere else).useProjectretry predicate atuseProject.ts:16-21, so behavior stays consistent between the two hooks.routes/_layout/$accountName/index.tsx:158-164which also special-cases 404.Frontend only. No backend changes.