WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

RetryAgent retried requests fail when body is FormData #4691

@eliotschu

Description

@eliotschu

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

undici/lib/core/util.js

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions