-
-
Notifications
You must be signed in to change notification settings - Fork 676
Description
Bug Description
If the body of a request made through RetryAgent is of type FormData, the request will fail if the RetryAgent actually has to retry the request.
Reproducible By
The small code example below is enough to reproduce this issue. If the first request succeeds, it works as expected, but if the first request fails and the RetryAgent attempts to retry the request, the error shown in Logs & Screenshots will be encountered.
/undici is simply a mock API route I created that return status 500 for the first request to force the RetryAgent to retry the request, then returns status 200 for any subsequent requests.
import { Agent, FormData, RetryAgent } from 'undici';
const agent = new RetryAgent(new Agent());
const formData = new FormData();
formData.append('field', 'test string');
const options = {
origin: 'http://localhost:3000',
path: '/undici',
method: 'PUT',
body: formData,
};
const response = await agent.request(options);
If body is replaced with a string instead of FormData and a content type of text/plain is specified as shown below, the retried request succeeds as expected.
import { Agent, FormData, RetryAgent } from 'undici';
const agent = new RetryAgent(new Agent());
const options = {
origin: 'http://localhost:3000',
path: '/undici',
method: 'PUT',
headers: {
'Content-Type': 'text/plain',
},
body: 'test string',
};
const response = await agent.request(options);
Expected Behavior
The RetryAgent should be able to handle FormData as the body when retrying requests.
Logs & Screenshots
node:buffer:777
throw new ERR_INVALID_ARG_TYPE(
^
TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer.
Received an instance of Array
at Function.byteLength (node:buffer:777:11)
at AsyncWriter.write (D:\athletic-repos\playground\node_modules\undici\lib\dispatcher\client-h1.js:1499:24)
at writeIterable (D:\athletic-repos\playground\node_modules\undici\lib\dispatcher\client-h1.js:1444:19) {
code: 'ERR_INVALID_ARG_TYPE'
}
Node.js v22.19.0
Environment
Windows 11 25H2, 26200.7171 and Node v22.19.0
Additional context
Disclosure that I did work with an AI agent to get this suggestion, but just adding a check for if the body is form data-like allows the RetryAgent to work as expected.
Above this section
Lines 61 to 69 in e3fedb0
| } else if ( | |
| body && | |
| typeof body !== 'string' && | |
| !ArrayBuffer.isView(body) && | |
| isIterable(body) | |
| ) { | |
| // TODO: Should we allow re-using iterable if !this.opts.idempotent | |
| // or through some other flag? | |
| return new BodyAsyncIterable(body) |
Add the following block
} else if (body && isFormDataLike(body)) {
return body