Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

OpenRouter adapter cannot retry 429 responses, even with `retryConfig` set

Open Beginner friendly
#1,473 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
75/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript

Research direction

The issue is in the OpenRouter adapter's text.ts file, specifically the chatStream, structuredOutput, and structuredOutputStream functions. Look at how the SDK's chat.send method is called; currently only signal and headers are passed. The fix is to add retryCodes to the request options, defaulting to ['5XX'] and allowing override via adapter config. Start by examining the linked SDK code to understand the retryCodes parameter, then modify the adapter to pass it through. Test with the provided reproduction script to ensure 429 responses are retried.

Written by the indexing model from the issue text.

Description

TanStack AI version

0.58.0

Framework/Library version

@tanstack/ai-openrouter: 0.19.17 | @openrouter/sdk: 0.13.20

Describe the bug and the steps to reproduce it

A 429 from OpenRouter is never retried by the OpenRouter adapter. Setting retryConfig on the adapter config does not change that. A 5xx is retried.

The SDK takes the retry strategy from the client (retryConfig), but the list of retryable status codes only from the per-call request options. It defaults to ["5XX"]. There is no client-level equivalent.

The adapter passes only signal and headers as per-call options, in chatStream(), structuredOutput() and structuredOutputStream(). So there is no way to opt 429 in.

Rate limits are the common transient failure on OpenRouter, especially when provider routing narrows a model to a single upstream provider. The OpenAI and Anthropic adapters retry 429 by default through their SDKs.

Steps to reproduce:

import { chat } from '@tanstack/ai'
import { createOpenRouterText } from '@tanstack/ai-openrouter'
import { HTTPClient } from '@openrouter/sdk/lib/http.js'

let calls = 0
const httpClient = new HTTPClient({
  fetcher: async () => {
    calls++
    return new Response(
      JSON.stringify({ error: { code: 429, message: 'Rate limit exceeded' } }),
      { status: 429, headers: { 'content-type': 'application/json', 'retry-after': '1' } },
    )
  },
})

const adapter = createOpenRouterText('openai/gpt-4o-mini', 'sk-or-test', {
  httpClient,
  retryConfig: {
    strategy: 'backoff',
    backoff: { initialInterval: 100, maxInterval: 1000, exponent: 1.5, maxElapsedTime: 3000 },
  },
})

for await (const chunk of chat({ adapter, messages: [{ role: 'user', content: 'Hello' }] })) {
  if (chunk.type === 'RUN_ERROR') console.log(chunk.message)
}
console.log(calls) // 1

Returning 503 instead of 429 from the same fetcher gives 5 calls.

Expected behavior

The adapter config accepts the SDK's retryCodes and forwards it to chat.send() next to signal and headers, e.g. retryCodes: ['429', '5XX']. Default behaviour stays as it is.

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

Inline above. No API key needed, the fetcher is stubbed.

Do you intend to try to help solve this bug with your own PR?

Yes, PR follows.

Terms & Code of Conduct
  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
Dominant language
TypeScript
Stars
3.1k
Forks
331
Avg merge
1d 10h
Merged PRs (30d)
130

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from TanStack/ai

All issues in TanStack/ai

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.