Bug Description
In apikeys mode, when a provider returns HTTP 429 (rate limit exceeded), the SDK correctly marks the provider as failed and fails over to the next provider. However, it never refunds the API key token, leaving the remaining balance
stranded with the original provider.
Expected Behavior
A 429 error should be treated like other non-retryable provider errors (e.g. 500, 502, 503, 504, 521): the SDK should call balanceManager.refundApiKey() to reclaim the unused balance before failing over.
Actual Behavior
The refund block in _handleErrorResponse does not include 429 in its status-code guard. The token is left behind unrefunded.
Relevant Code
File: @sdk/client/RoutstrClient.ts
Method: _handleErrorResponse
The refund logic is gated behind this condition (approx. line 598):
if (
(status === 401 ||
status === 403 ||
status === 413 ||
status === 400 ||
status === 500 ||
status === 502 ||
status === 503 ||
status === 504 ||
status === 521) &&
!tryNextProvider
) {
// ... refundApiKey / receiveToken logic
}
429 is missing from this list.
Logs
[RoutstrClient] _handleErrorResponse: status=429, baseUrl=https://api.nonkycai.com/, mode=apikeys, ...
[RoutstrClient] _handleErrorResponse: Attempting to receive/restore token for https://api.nonkycai.com/
Error in walletAdapter receiveToken: proofs already spent <-- initial receiveToken fails (expected)
[RoutstrClient] _handleErrorResponse: Failed to receive token: proofs already spent
...
[markFailed:...] Updated lastFailed map for https://api.nonkycai.com/ ...
[RoutstrClient] _handleErrorResponse: Marked provider https://api.nonkycai.com/ as failed
[RoutstrClient] _handleErrorResponse: Failing over to next provider: https://staging.routstr.com/
Notice: no refundApiKey call appears in the logs. The balance (2074000 msat) is never recovered.
Suggested Fix
Add status === 429 to the condition list in _handleErrorResponse, or extract the list into a configurable/set of refund-eligible status codes so rate limits are handled consistently.
Environment
Bug Description
In
apikeysmode, when a provider returns HTTP 429 (rate limit exceeded), the SDK correctly marks the provider as failed and fails over to the next provider. However, it never refunds the API key token, leaving the remaining balancestranded with the original provider.
Expected Behavior
A 429 error should be treated like other non-retryable provider errors (e.g. 500, 502, 503, 504, 521): the SDK should call
balanceManager.refundApiKey()to reclaim the unused balance before failing over.Actual Behavior
The refund block in
_handleErrorResponsedoes not include429in its status-code guard. The token is left behind unrefunded.Relevant Code
File:
@sdk/client/RoutstrClient.tsMethod:
_handleErrorResponseThe refund logic is gated behind this condition (approx. line 598):
429 is missing from this list.
Logs
Notice: no refundApiKey call appears in the logs. The balance (2074000 msat) is never recovered.
Suggested Fix
Add status === 429 to the condition list in _handleErrorResponse, or extract the list into a configurable/set of refund-eligible status codes so rate limits are handled consistently.
Environment