Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Failed to parse body as FormData with Axios #3676

Closed
kettanaito opened this issue Oct 4, 2024 · 11 comments · Fixed by #3677
Closed

TypeError: Failed to parse body as FormData with Axios #3676

kettanaito opened this issue Oct 4, 2024 · 11 comments · Fixed by #3677
Labels
bug Something isn't working

Comments

@kettanaito
Copy link
Contributor

kettanaito commented Oct 4, 2024

Bug Description

When performing a POST request with FormData and Axios, Undici fails to parse the request body.

Reproducible By

import axios from 'axios'
import { http } from 'msw'
import { setupServer } from 'msw/node'

const server = setupServer(
  http.post('*/upload', async ({ request }) => {
    // This is a regular Request instance constructed using Undici.
    const data = await request.formData()
    return Response.json(data)
  })
)
server.listen()

const request = axios.create({
  baseURL: 'https://example.com/upload',
  onUploadProgress() {},
})

const formData = new FormData()
const file = new Blob(['Hello', 'world'], { type: 'text/plain' })
formData.set('file', file, 'doc.txt')

const response = await request.post('https://example.com/upload', formData).catch(error => {
  throw error.response.data
})

This throws the following error:

{
  name: 'TypeError',
  message: 'Failed to parse body as FormData.',
  stack: 'TypeError: Failed to parse body as FormData.\n' +
    '    at node:internal/deps/undici/undici:5415:27\n' +
    '    at successSteps (node:internal/deps/undici/undici:5459:27)\n' +
    '    at fullyReadBody (node:internal/deps/undici/undici:4378:9)\n' +
    '    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n' +
    '    at async consumeBody (node:internal/deps/undici/undici:5468:7)\n' +
    '    at async file:///mswjs/msw/repro.mjs:8:18\n' +
    '    at async file:///mswjs/msw/lib/core/handlers/RequestHandler.mjs:121:24\n' +
    '    at async HttpHandler.run (file:///mswjs/msw/lib/core/handlers/RequestHandler.mjs:107:28)\n' +
    '    at async executeHandlers (file:///mswjs/msw/lib/core/utils/executeHandlers.mjs:10:14)\n' +
    '    at async until (file:///mswjs/msw/node_modules/.pnpm/@[email protected]/node_modules/@open-draft/until/lib/index.mjs:4:18)'
}

Node.js v22.3.0

I have a strong reason to believe something has changed in Undici between Node.js v21 and v22, which is causing this parsing issue. This same scenario is passing with the same dependencies using Node.js v18-v20.

Expected Behavior

Undici parses the FormData body sent from Axios.

Logs & Screenshots

Here's the FormData body read as text. This looks okay to me.

--axios-1.6.8-boundary-3Jx5-4T27f9Yo6Ul865QObiBm
Content-Disposition: form-data; name="file"; filename="doc.txt"
Content-Type: text/plain

Helloworld
--axios-1.6.8-boundary-3Jx5-4T27f9Yo6Ul865QObiBm--

Environment

  • Node v22.3.0
  • Axios v1.6.8 (the behavior is the same on the latest Axios version v1.7.7)
@kettanaito kettanaito added the bug Something isn't working label Oct 4, 2024
@kettanaito
Copy link
Contributor Author

Can it be that Undici became strict to who constructs the FormData? The headers of the data clearly feature some Axiom boundary. Can that be the thing that upsets Undici? Does it only accept FormData instances created by itself?

@KhafraDev
Copy link
Member

Could you provide an example that doesn't use axios or msw? I'd need the exact body (including \r\n's) and the content-type header to assess.

@kettanaito
Copy link
Contributor Author

@KhafraDev, that doesn't seem to be possible. I can omit MSW since it has nothing to do with this scenario, but the issue is specific to Axios. If you feel raising it with Axios is a better approach, I will do so. If nothing rings a bell by looking at the payload above, then I suppose the FormData payload is okay.

I can share the request body as buffer, which should preserve the newlines and other characters. Would that help?

@KhafraDev
Copy link
Member

I need the raw body and the content-type header.

@KhafraDev
Copy link
Member

KhafraDev commented Oct 4, 2024

I found a repro without dependencies. Will have a fix soon.

const response = new Response([
  '--axios-1.7.7-boundary-bPgZ9x77LfApGVUN839vui4V7\r\n' +
  'Content-Disposition: form-data; name="file"; filename="doc.txt"\r\n' +
  'Content-Type: text/plain\r\n' +
  '\r\n' +
  'Helloworld\r\n' +
  '--axios-1.7.7-boundary-bPgZ9x77LfApGVUN839vui4V7--\r\n' +
  '\r\n',
].join(''), {
  headers: {
    'content-type': 'multipart/form-data; boundary=axios-1.7.7-boundary-bPgZ9x77LfApGVUN839vui4V7'
  }
})

await response.formData()

@kettanaito
Copy link
Contributor Author

Thank you for fixing this, @KhafraDev! Amazing job, as always.

@539hex
Copy link

539hex commented Nov 22, 2024

Hi, in which version of node is this fixed ? @KhafraDev i am using node 23.3.0 and got the same issue

@SilvanBauser
Copy link

This popped up again as of last week in Node 22 & 23.

@busy-mango
Copy link

Bug Description

When performing a POST request with FormData and Axios, Undici fails to parse the request body.

Reproducible By

import axios from 'axios'
import { http } from 'msw'
import { setupServer } from 'msw/node'

const server = setupServer(
http.post('*/upload', async ({ request }) => {
// This is a regular Request instance constructed using Undici.
const data = await request.formData()
return Response.json(data)
})
)
server.listen()

const request = axios.create({
baseURL: 'https://example.com/upload',
onUploadProgress() {},
})

const formData = new FormData()
const file = new Blob(['Hello', 'world'], { type: 'text/plain' })
formData.set('file', file, 'doc.txt')

const response = await request.post('https://example.com/upload', formData).catch(error => {
throw error.response.data
})
This throws the following error:

{
  name: 'TypeError',
  message: 'Failed to parse body as FormData.',
  stack: 'TypeError: Failed to parse body as FormData.\n' +
    '    at node:internal/deps/undici/undici:5415:27\n' +
    '    at successSteps (node:internal/deps/undici/undici:5459:27)\n' +
    '    at fullyReadBody (node:internal/deps/undici/undici:4378:9)\n' +
    '    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n' +
    '    at async consumeBody (node:internal/deps/undici/undici:5468:7)\n' +
    '    at async file:///mswjs/msw/repro.mjs:8:18\n' +
    '    at async file:///mswjs/msw/lib/core/handlers/RequestHandler.mjs:121:24\n' +
    '    at async HttpHandler.run (file:///mswjs/msw/lib/core/handlers/RequestHandler.mjs:107:28)\n' +
    '    at async executeHandlers (file:///mswjs/msw/lib/core/utils/executeHandlers.mjs:10:14)\n' +
    '    at async until (file:///mswjs/msw/node_modules/.pnpm/@[email protected]/node_modules/@open-draft/until/lib/index.mjs:4:18)'
}

Node.js v22.3.0

I have a strong reason to believe something has changed in Undici between Node.js v21 and v22, which is causing this parsing issue. This same scenario is passing with the same dependencies using Node.js v18-v20.

Expected Behavior

Undici parses the FormData body sent from Axios.

Logs & Screenshots

Here's the FormData body read as text. This looks okay to me.

--axios-1.6.8-boundary-3Jx5-4T27f9Yo6Ul865QObiBm
Content-Disposition: form-data; name="file"; filename="doc.txt"
Content-Type: text/plain

Helloworld
--axios-1.6.8-boundary-3Jx5-4T27f9Yo6Ul865QObiBm--

Environment

  • Node v22.3.0
  • Axios v1.6.8 (the behavior is the same on the latest Axios version v1.7.7)

reopen this issue plz

@busy-mango
Copy link

This popped up again as of last day in Node 20.13.0 ~ 23.6.0

OS: macOS 14.6.1
CPU: (8) Intel Core i9
Memory: 32.00 GB
Shell: 5.9 - /bin/zsh

curl --location --request POST 'http://localhost:3000/api/icon/update' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--header 'Accept: */*' \
--header 'Host: 10.98.108.52:3000' \
--header 'Connection: keep-alive' \
--header 'Content-Type: multipart/form-data; boundary=--------------------------827192901737642659031343' \
--form 'svg=@"/Users/mangosetsuna/Pictures/Icons/attachment.svg"'

@metcoder95
Copy link
Member

This issue has been closed for three months, please open a new issue if you consider the issue appeared once more. Do no forget to add an Minimum Reproducible Example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants