{"id":17389,"library":"undici-retry","title":"undici-retry","description":"undici-retry is a JavaScript/TypeScript library designed to integrate robust retry logic with the undici HTTP client. As of version 7.0.0, it provides mechanisms to automatically re-attempt failed HTTP requests based on configurable criteria such as status codes, timeouts, and custom delay resolvers. It is tightly coupled with `undici`, requiring `undici` version 7.0.0 or higher as a peer dependency, and is compatible with Node.js environments version 20 or newer. The library offers two primary functions: `sendWithRetry` for operations where the response body is consumed directly (e.g., JSON parsing), and `sendWithRetryReturnStream` for scenarios requiring stream-based body handling, which is crucial for large responses or custom stream processing. Its release cadence typically aligns with major `undici` releases, adapting to `undici`'s API changes and Node.js version support. Key differentiators include its tight integration with `undici`'s `Dispatcher` and `Client` types, and its `Either` pattern for error handling.","status":"active","version":"7.0.0","language":"javascript","source_language":"en","source_url":"git://github.com/kibertoad/undici-retry","tags":["javascript","undici","retry","error","http","client","https","typescript"],"install":[{"cmd":"npm install undici-retry","lang":"bash","label":"npm"},{"cmd":"yarn add undici-retry","lang":"bash","label":"yarn"},{"cmd":"pnpm add undici-retry","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core HTTP client for all network operations; undici-retry builds directly on its API and types.","package":"undici","optional":false}],"imports":[{"note":"The library is primarily ESM. Using CommonJS `require` with default Node.js settings will likely fail.","wrong":"const sendWithRetry = require('undici-retry').sendWithRetry","symbol":"sendWithRetry","correct":"import { sendWithRetry } from 'undici-retry'"},{"note":"Used for requests where the response body needs to be processed as a Node.js Readable stream, rather than being automatically consumed.","wrong":"const { sendWithRetryReturnStream } = require('undici-retry')","symbol":"sendWithRetryReturnStream","correct":"import { sendWithRetryReturnStream } from 'undici-retry'"},{"note":"This is a named export for a common constant, not part of a default export.","wrong":"import undiciRetry from 'undici-retry'; undiciRetry.DEFAULT_RETRYABLE_STATUS_CODES","symbol":"DEFAULT_RETRYABLE_STATUS_CODES","correct":"import { DEFAULT_RETRYABLE_STATUS_CODES } from 'undici-retry'"},{"note":"Always use `import type` for type-only imports to prevent bundling issues and improve clarity in TypeScript.","wrong":"import { RetryConfig, RequestParams } from 'undici-retry'","symbol":"RetryConfig, RequestParams","correct":"import type { RetryConfig, RequestParams } from 'undici-retry'"}],"quickstart":{"code":"import { sendWithRetry, DEFAULT_RETRYABLE_STATUS_CODES } from 'undici-retry';\nimport type { RetryConfig, RequestParams} from 'undici-retry'\nimport { Client } from 'undici';\nimport type { Dispatcher } from 'undici';\n\nconst client = new Client('http://localhost:3000', {}); // Replace with your target URL\n\nasync function makeRetriableRequest() {\n    const request: Dispatcher.RequestOptions = {\n        method: 'GET',\n        path: '/',\n        bodyTimeout: 500,\n        headersTimeout: 500,\n    };\n\n    const retryConfig: RetryConfig = {\n        maxAttempts: 3,\n        statusCodesToRetry: [429, 500, 502, 503, 504], // Customize retryable status codes\n        retryOnTimeout: true,\n        // delayResolver: (response, statusCodesToRetry) => { /* custom logic */ return 1000; }\n    };\n\n    const requestParams: RequestParams = {\n        safeParseJson: true,\n        blobBody: false,\n        throwOnInternalError: false,\n    };\n\n    console.log('Attempting request with retry logic...');\n    const result = await sendWithRetry(client, request, retryConfig, requestParams);\n\n    if (result.error) {\n        console.error('Request failed after all retries:');\n        console.error(JSON.stringify({\n            body: result.error.body, // The last error response body\n            headers: result.error.headers,\n            statusCode: result.error.statusCode,\n            message: result.error.error?.message, // Error message if an internal error occurred\n        }, null, 2));\n    } else if (result.result) {\n        console.log('Request successful:');\n        console.log(JSON.stringify({\n            body: result.result.body,\n            headers: result.result.headers,\n            statusCode: result.result.statusCode,\n        }, null, 2));\n    }\n\n    await client.close(); // Important: Close the client when no longer needed\n}\n\nmakeRetriableRequest();","lang":"typescript","description":"Demonstrates how to perform an HTTP GET request with retry logic using `sendWithRetry`, configure retry parameters, and handle the `Either` result for both success and failure scenarios."},"warnings":[{"fix":"Always ensure your installed `undici` version matches the peer dependency requirement of `undici-retry` (e.g., `npm install undici@7`). Check the `package.json` for precise peer dependency ranges.","message":"Major versions of `undici-retry` are tightly coupled to specific major versions of its `undici` peer dependency. For instance, `undici-retry@4.x` requires `undici@6.x`, and `undici-retry@7.x` requires `undici@7.x`.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Upgrade your Node.js environment to version 20 or higher. Using `nvm` or a similar tool is recommended for managing Node.js versions.","message":"`undici-retry` versions 4.0.0 and above dropped support for Node.js 16. Newer versions require Node.js >=20.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Always ensure the returned `Readable` stream from `result.result.body` is fully consumed or explicitly `await result.result.body.dump()` if the content is not needed, to release the underlying connection.","message":"When using `sendWithRetryReturnStream`, the response body is returned as a Node.js `Readable` stream and is NOT automatically consumed. Failure to consume (e.g., by reading `stream.text()`, `stream.json()`, `stream.blob()`, or piping it) or explicitly dump (`stream.dump()`) the stream will lead to connection leaks and eventual `undici` resource exhaustion.","severity":"gotcha","affected_versions":"*"},{"fix":"If you prefer internal errors to be thrown as exceptions (e.g., for standard try-catch blocks), set `throwOnInternalError: true` in your `requestParams` or `streamParams`.","message":"By default, `throwOnInternalError` is `false` in `RequestParams` and `StreamedResponseRequestParams`. This means network-level errors (like `ECONNREFUSED` or `ENOTFOUND`) will be captured and returned within the `result.error` object, rather than throwing an exception.","severity":"gotcha","affected_versions":"*"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure your project is configured for ESM (e.g., `\"type\": \"module\"` in `package.json`) and use `import { sendWithRetry } from 'undici-retry';`. If strictly bound to CommonJS, you might need a dynamic `import()` or transpilation.","cause":"Attempting to use `require()` to import `undici-retry` functions in a CommonJS context when the library is primarily designed for ESM.","error":"TypeError: (0 , undici_retry_1.sendWithRetry) is not a function"},{"fix":"Install the correct version of `undici` that matches the peer dependency declared by your `undici-retry` version. For `undici-retry@7.x`, run `npm install undici@7`.","cause":"The installed version of `undici` does not satisfy the peer dependency requirements of `undici-retry`.","error":"npm ERR! ERESOLVE unable to resolve dependency tree ... undici-retry@X.Y.Z requires a peer of undici@A.B.C but none is installed."},{"fix":"Review all calls to `sendWithRetryReturnStream` and ensure that `result.result.body` is either fully consumed (e.g., `await stream.text()`) or explicitly dumped (`await stream.dump()`) after use.","cause":"Likely due to unconsumed or undumped response bodies from `sendWithRetryReturnStream`, leading to `undici` connection pool exhaustion.","error":"Error: Request aborted by client. Reason: Aborted with cause: The connection was closed before the request could be completed."}],"ecosystem":"npm","meta_description":null}