Skip to content

apikeys mode: 429 rate-limit errors skip refund logic, leaving tokens stranded on provider #196

@sh1ftred

Description

@sh1ftred

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


  ---

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions