Summary
When a client exceeds the rate limit on the public registry API, @fastify/rate-limit surfaces as an HTTP 500 (INTERNAL_ERROR, isOperational: false) instead of a proper 429 Too Many Requests. Clients can't distinguish throttling from a real server fault, and it pollutes error monitoring with non-actionable 500s.
Evidence
Observed against staging during a burst of SDK integration requests (make smoke). Single requests succeed (200); rapid bursts from one IP trip the limiter and return 500:
url: /v1/bundles/@nimblebraininc/echo/versions
statusCode: 500
errorCode: INTERNAL_ERROR
isOperational: false
stack: Error: Rate limit exceeded, retry in 39 seconds
at Object.defaultErrorResponse [as errorResponseBuilder]
(@fastify/rate-limit/index.js:32:15)
The rate-limit plugin throws an Error that the global error handler classifies as non-operational → 500.
Expected
- Status 429 with
Retry-After header
- A
RATE_LIMITED / operational error code (not INTERNAL_ERROR)
- Not logged as a level-50 internal error
Likely fix
Configure @fastify/rate-limit's errorResponseBuilder to return a 429 payload (and/or map it in the global error handler), so it's treated as operational.
Notes
Pre-existing; surfaced during the #119 deploy smoke run. The 500s there were this limiter behavior, not a regression. Low severity (functionality works) but worth fixing for client ergonomics and clean monitoring.
Summary
When a client exceeds the rate limit on the public registry API,
@fastify/rate-limitsurfaces as an HTTP 500 (INTERNAL_ERROR,isOperational: false) instead of a proper 429 Too Many Requests. Clients can't distinguish throttling from a real server fault, and it pollutes error monitoring with non-actionable 500s.Evidence
Observed against staging during a burst of SDK integration requests (
make smoke). Single requests succeed (200); rapid bursts from one IP trip the limiter and return 500:The rate-limit plugin throws an
Errorthat the global error handler classifies as non-operational → 500.Expected
Retry-AfterheaderRATE_LIMITED/ operational error code (notINTERNAL_ERROR)Likely fix
Configure
@fastify/rate-limit'serrorResponseBuilderto return a 429 payload (and/or map it in the global error handler), so it's treated as operational.Notes
Pre-existing; surfaced during the #119 deploy smoke run. The 500s there were this limiter behavior, not a regression. Low severity (functionality works) but worth fixing for client ergonomics and clean monitoring.