Skip to article

Retry policy

Opt into bounded retries for transient failures while preserving the complete call deadline.

On this page

Normalized search retries

retry.ts · fixture
import { createSearch } from '@belweave/search-sdk';
import { createMockProvider } from '@belweave/search-sdk/testing';

const provider = createMockProvider({ outcomes: [
  { type: 'error', code: 'rate_limit', retryAfterMs: 10 },
  { type: 'success' },
] });
const client = createSearch({
  provider,
  timeoutMs: 5_000,
  retry: { maxRetries: 1, baseDelayMs: 25, maxDelayMs: 200 },
});
const response = await client.web.search({ query: 'SQLite concurrency' });
console.log(response.attempts.length); // 2, same provider; no fallback_used

Additional attempts occur per provider before moving to an explicit fallback. Transient categories are network, rate_limit, unavailable, and attempt_timeout. Terminal validation, auth, caller cancellation, and total-deadline failures are not retried.

Backoff settings

SettingContract
maxRetriesAdditional attempts, integer 0–5; default 0.
baseDelayMsPositive integer starting delay; default 250.
maxDelayMsPositive integer exponential cap; default 5,000; at least baseDelayMs.

Backoff uses jitter and never shortens a parsed Retry-After value. If the required delay cannot fit inside the remaining deadline, the operation fails with timeout instead of retrying early. Retrying can repeat billable work.

Native operations require eligibility too

A native transport retry policy alone does not make every operation replayable. The operation must explicitly declare retryable: true; the default is false, including for GET. Provider create/write/delete methods remain non-retrying unless their static mapping deliberately declares otherwise. There is no claim of provider idempotency.

Native retry categories are transport errors and HTTP 429, 408, or 5xx. Malformed JSON, authentication failures, and stream consumption are not retried.