Msw: Uncaught (in promise) SyntaxError: Unexpected end of input

Created on 6 Jun 2020  路  7Comments  路  Source: mswjs/msw

Describe the bug

After updating the msw package from 0.15.5 to 0.19.0 and update the mockServiceWorker.js file, the service worker started throwing the following error

Uncaught (in promise) SyntaxError: Unexpected end of input at line 111

After some debugging I was able to fix the issue ( at least for me ) by replacing

 const body = request.headers.get('content-type')?.includes('json')
        ? await request.json()
        : await request.text()

with

const isJSONContentType = request.headers.get('content-type')?.includes('json')
let body;
if (isJSONContentType) {
  try {
    body = await request.json()
  } catch (error) {
    console.warn(error)
    body = await request.text()
    console.log({body,headers: Object.fromEntries(request.headers.entries()), url: request.url})
  }
} else  {
  body = await request.text()
}

with this fix I'm getting the correct mocked responses but what I don't understand is why the body is showing up empty

Environment

  • msw: 0.19.0
  • nodejs: 12.13.1
  • npm: 6.14.5
  • webpack: 4.42.1
  • webpack-dev-server: 3.10.3

The requests that are failing match with a Webpack DevServer proxy that I have in my environment.
The proxy takes every request url starting with "/api" to a live server

Webpack devServer config:

devServer: {
    contentBase: "./public",
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept"
    },
    host: !process.argv.join(" ").includes("--sw") && require("ip").address(),
    disableHostCheck: true,
    open: true,
    hot: false,
    port,
    proxy: {
      "/api": {
        target: "https://live.server.domain.cloud",
        secure: false,
        changeOrigin: true,
        withCredentials: true,
      }
    }
  },

Please also provide your browser version.

Chrome 83.0.4103.61

To Reproduce

Steps to reproduce the behaviour:

  1. Run the webapp with msw enabled
  2. in the console you'll see the error Uncaught (in promise) SyntaxError: Unexpected end of input
  3. if you refresh the browser you'll find that the request for the webpack index.html file is hanging and will not resolve

Expected behavior

Shouldn't throw if the suspected response has the Content-Type header containing "json" and the body is empty

Screenshots

Original error

image

chrome console after I added some logs and error handling on mockServiceWorker.js

image

Network tab of the same session / request after the fix showing expected mocked data

image

bug browser

Most helpful comment

Having the same issue. I suppose it's because of the dev proxy server. I use create-react-app and this is my setupProxy.js file:

const { createProxyMiddleware } = require('http-proxy-middleware')

module.exports = function (app) {
  app.use(
    ['/auth', '/api'],
    createProxyMiddleware({
      target: process.env.DEV_PROXY,
      changeOrigin: true,
    }),
  )
}

This is how I make a request:

window.fetch(url, {
  headers: {
    'Content-Type': 'application/json',
  },
})

Before the setupProxy.js file was created, msw worked fine.

All 7 comments

Hey, @mouhannad-sh. Thanks for reporting this.

Let me clarify: is the empty body ("") intended, or is the actual body set, but for some reason is being empty in the worker?

Historically, there has been a fallback from a failed .json() to .text() when retrieving a body. However, we wanted to encourage developers to respect the Content-Type header, so when it's set to */json the body must be a valid JSON. Now I see that this doesn't cover the empty body scenario.

I'm thinking whether we even need to determine if it's JSON or not. Thing is, right after retrieving the body, it gets stringified in sentToClient anyway. It should be much safer and error-prone to always get the textual body, send it to the client, and _then_ figure out whether to parse or not.

Error handling in such case is delegated to the client, which makes any potential issues solvable on the client-side library, without having to touch the worker file. The intention is that the worker file should be the bare minimum, the one that needs almost no maintenance at all.

Additionally, in the current implementation of the client-side parsing of the worker message, we already check for empty strings, and prevent parsing as JSON in that case:

https://github.com/mswjs/msw/blob/5defbf2b4f4d7ae1503cb68a4e7be14e994b3f7d/src/utils/parseRequestBody.ts#L4-L18

I really think we should do only this when handling request body in the worker:

const reqBody = await request.text()

I'd expect that to handle even the binary files, converting blobs to text, and then letting the client-side library parsing to decide how to parse that.

@mouhannad-sh, please, would you be interested in helping me with this fix? I'd gladly assist in code reviews and share any necessary insights about the library.

Thanks for the quick response @kettanaito 馃憤
I'm currently on the go, I'll put up a PR for this ASAP

@mouhannad-sh, hey, no worries! Whenever you have a spare time for this.
Your involvement is highly appreciated! Thank you.

Let me clarify: is the empty body ("") intended, or is the actual body set, but for some reason is being empty in the worker?

unfortunately It's the latter, even though everything in the browser is working as expected, all of my mocked responses are coming in correctly in the network tab, the empty responses are only showing in the worker file

Having the same issue. I suppose it's because of the dev proxy server. I use create-react-app and this is my setupProxy.js file:

const { createProxyMiddleware } = require('http-proxy-middleware')

module.exports = function (app) {
  app.use(
    ['/auth', '/api'],
    createProxyMiddleware({
      target: process.env.DEV_PROXY,
      changeOrigin: true,
    }),
  )
}

This is how I make a request:

window.fetch(url, {
  headers: {
    'Content-Type': 'application/json',
  },
})

Before the setupProxy.js file was created, msw worked fine.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

otaciliolacerda picture otaciliolacerda  路  3Comments

PritamSangani picture PritamSangani  路  3Comments

dashed picture dashed  路  3Comments

dashed picture dashed  路  4Comments

otaciliolacerda picture otaciliolacerda  路  3Comments