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

Failed to construct 'Response': The status provided (0) is outside the range [200, 599] #529

Closed
Yagogc opened this issue Jan 8, 2021 · 27 comments · Fixed by #564
Closed
Assignees
Labels
bug Something isn't working needs:reproduction scope:browser Related to MSW running in a browser

Comments

@Yagogc
Copy link

Yagogc commented Jan 8, 2021

Environment

Name Version
msw 0.25.0
browser Chrome
OS macOS

Request handlers

// ./mocks/handlers.js

import { graphql } from 'msw'

const handlers = [
  graphql.mutation('bookAppointment', (_req, res, ctx) => res(ctx.status(422, 'Error 422 custom'))),
]

export default handlers
// ./mocks/browser.js

import { setupWorker } from 'msw'
import handlers from './handlers'

const worker = setupWorker(...handlers)

export { worker }
// ./index.js

if (process.env.NODE_ENV === 'development') {
    const { worker } = require('./mocks/browser')
    worker.start()
}

Actual request

import gql from 'graphql-tag'

export default gql`
  mutation bookAppointment($input: AppointmentRequestInput!) {
    bookAppointment(input: $input) {
        ...
      }
    }
  }
`

Current behavior

When running the react application I'm getting the following logs:

[MSW] Mocking enabled.

index.js:1034 Uncaught RangeError: Failed to construct 'Response': The status provided (0) is outside the range [200, 599].
    at index.js:1034
    at ServiceWorkerContainer.<anonymous> (index.js:1200)

Obviously the MSW is not intercepting said mutation...

Any ideas? I'm guessing that I'm making a silly mistake that I'm not able to see -_-

Expected behavior

The only log I should see is the MSW getting initialise:

[MSW] Mocking enabled.
@Yagogc Yagogc added bug Something isn't working scope:browser Related to MSW running in a browser labels Jan 8, 2021
@marcosvega91
Copy link
Member

marcosvega91 commented Jan 8, 2021

Hi @Yagogc, I'm pretty sure what is happening here.

In the latest release, we have introduced event handling. When the service worker receives a response from a request it will be sent to the client and the user could listen for response:mocked and response:bypass events.

Before it a new Response object is created using the data received by service worker. There are some cases where the the data of the service worker has a field status equal to 0. These cases are described here https://fetch.spec.whatwg.org

A network error is a response whose status is always 0,

An opaque filtered response is a filtered response whose type is "opaque", URL list is the empty list, status is 0, status > > message is the empty byte sequence, header list is empty, and body is null.

An opaque-redirect filtered response is a filtered response whose type is "opaqueredirect", status is 0, status message is > the empty byte sequence, header list is empty, and body is null.

The network error can be handled using Response.error() but I'm not sure how to create a Response for the other two cases. Maeby we have to polyfill the Response ? @kettanaito

@kettanaito
Copy link
Member

Hey, @Yagogc. Thanks for reporting this.

I'll set up a test scenario that reproduces this. Hopefully, it'll help us find the right solution to the issue.

Thanks for the investigation, @marcosvega91. I suspect you're right, still will follow up after I have the test failing.

@kettanaito kettanaito self-assigned this Jan 9, 2021
@lwhiteley
Copy link

lwhiteley commented Jan 10, 2021

Watching as I'm getting the same behaviour with rest mocking.

It is also affecting image requests that have nothing to do with the mocked request (not sure if related).

@kettanaito
Copy link
Member

Taking this stack trace into account, the exception seems to originate from the Service Worker file:

[MSW] Mocking enabled.

index.js:1034 Uncaught RangeError: Failed to construct 'Response': The status provided (0) is outside the range [200, 599].
    at index.js:1034
    at ServiceWorkerContainer.<anonymous> (index.js:1200)

The only place where we construct a Response instance in mockServiceWorker.js is here:

function createResponse(clientMessage) {
return new Response(clientMessage.payload.body, {
...clientMessage.payload,
headers: clientMessage.payload.headers,
})
}

clientMessage.payload is what the client-side library sends to the worker (a mocked response, the result of res(...) call).

@lwhiteley, may I please ask for your help in reproducing this issue? I've written the following test, but it passes:

const worker = setupWorker(
  graphql.mutation('BookAppointment', (req, res, ctx) => {
    return res(ctx.status(422, 'Custom status text'))
  }),
)

test('handles 0 response status code', async () => {
  const runtime = await createRuntime()

  const res = await executeOperation(runtime.page, {
    query: `
      mutation BookAppointment {
        appointment {
          id
        }
      }
    `,
  })
  const status = res.status()
  const statusText = res.statusText()

  expect(status).toBe(422)
  expect(statusText).toBe('Custom status text')

  return runtime.cleanup()
})

I also confirm that it works as expected on runtime. If you can, would you mind to contribute a pull request with a failing test? We have the Contribution guidelines on how to do that, so don't worry if you've never done something like this before. We'd be glad to have you involved and will help once there's a reproducible test. Thanks!

@lwhiteley
Copy link

lwhiteley commented Jan 11, 2021

@kettanaito I wont be able to do any investigation until weekend or possibly in the evening for me.

but i can let you know my observations for now.

Issues:

  • In my app the error only happens on pages where the mocked request is never invoked.
  • Images also turn up blank when the service worker is enabled on the pages where the mocked request is never invoked. the image requests dont fail so this can only be verifiable by a visual test or somehow testing the image binary returned to see if its actually different

Notes:

  • the two above points can be entirely isolated issues but i wont know until there is an investigation

@kettanaito
Copy link
Member

kettanaito commented Jan 12, 2021

In my app the error only happens on pages where the mocked request is never invoked.

This seems odd. If that's the case, then the only point where MSW may cause such an exception is when handling a bypass request (the one that doesn't have a request handler, i.e. static assets).

This is also contradictory to your original description: you mock a bookAppointment mutation and say that MSW should intercept it (expected behavior). Now you're highlighting that the issue happens only when the mocked request is never invoked. Sorry, I'm a little lost at this.

Please, may I ask you to provide a reproduction repository with this issue? I was unsuccessful in reproducing it in a test using your example above—the test passes and the mutation is intercepted.

@lwhiteley
Copy link

@kettanaito i think you're mixing my specific issue with the issue of the original reporter.
The original reporter has a graphql example.

Im saying that this same error happens for mocking rest endpoints (may be irrelevant) as well and my observations are purely based on behaviours i saw when i included the service worker in my app.
When i disabled msw everything works fine

@lwhiteley
Copy link

lwhiteley commented Jan 12, 2021

@kettanaito

https://github.com/lwhiteley/msw-error-reproduce

here is a reproduction.

As you can see, i mocked the request but in the app i never actually invoke it .. as this is a fresh create-react-app template without any mods except msw

Screenshot 2021-01-12 at 13 58 23

unfortunately it doesnt happen all the time but im trying to replicate it definitely as it always happens in my app

@lwhiteley
Copy link

lwhiteley commented Jan 12, 2021

@kettanaito ive updated the example to increase possibility of it happening ..

https://github.com/lwhiteley/msw-error-reproduce

How to reproduce:

  • Let app load and all requests resolved.
  • then click open modal
    • the modal will trigger some additional requests

check the console for the error

Screenshot 2021-01-12 at 14 47 02

@kettanaito
Copy link
Member

@lwhiteley my bad, I've indeed mixed those two issues. Thank you for preparing that repo, I'll check it out and perhaps both issues will have the same cause.

@nvh95
Copy link
Contributor

nvh95 commented Jan 18, 2021

I just encountered the exact same issue as @lwhiteley's. But the mocks are not broken.
Screenshot 2021-01-18 at 12 29 01

My handlers look like this:

// mocks/handlers.js
import { rest } from 'msw';


export const handlers = [
  rest.get('*/an_end_point', (req, res, ctx) => res(ctx.json({
    data: {
      something: {
        data: {
          property_a: 1.0,
          property_b: 1.0
        }
      }
    }
  })))
];

Other files:

// index.js
...
const { worker } = require('./mocks/browser');
worker.start();
...
// mocks/browser.js
import { setupWorker, rest } from 'msw';
import { handlers } from './handlers';
// This configures a Service Worker with the given request handlers.
export const worker = setupWorker(...handlers);

// Make the `worker` and `rest` references available globally,
// so they can be accessed in both runtime and test suites.
window.msw = {
  worker,
  rest,
};

I can make a repository if it's needed @kettanaito

@KnisterPeter
Copy link
Contributor

For me this happens for CORS requests (not sure if for all).
But unhandled (unmocked) requests from foreign domain seem to return a invalid response object which is failed to get cloned.

@rubenmoya
Copy link

I'm having the same problem, downgrading to the 0.24.0 "fixes" it in the meantime in case someone is blocked.

@Justinohallo
Copy link

Having the same issue.

I have the exact set up as listed in the documentation.

@timdeschryver
Copy link
Member

timdeschryver commented Jan 18, 2021

Seems like the culprit here are CORS requests, that don't have CORS headers included on the response.
These requests "hide" some properties on the response, for example status, but also the response body.
See fetch docs for more info.

I'm not sure, but I think we won't be able to return a Response object within the response lifecycle? 🤔 At least, not for these requests...

@AriPerkkio
Copy link
Contributor

Seeing this as well after upgrading to 25.

Some debugging info here, looks like this one hasn't been reported yet.

const response = new Response(payload.body, payload)

function createResponseListener(context) {
    return (_, message) => {
        const { payload } = message;
        if(!payload || !payload.status) {
            console.log('Payload status 0 or missing', payload);
            debugger
        }
        const response = new Response(payload.body, payload);
        ...

Active request on network tab is for react-devtools: chrome-extension://<some-hash>/build/react_devtools_backend.js

If I disable react-devtools extension I'm unable to reproduce this issue. Immediately when dev-tools are activated this issue comes up all the time. Should MSW somehow filter out these extension requests?

@xclw2000
Copy link

same issue here, Only occur the first page load after execute npm run start command.
If refresh the page, every thing is OK, unless I restart the dev server

@kettanaito
Copy link
Member

@AriPerkkio that's a good insight. I think the issue is connected to #536, as MSW may be attempting to handle a request originating from a different source than the client-side of MSW (i.e. React DevTools).

@timdeschryver, thank you for the update on that! If there's a CORS request without CORS headers in the response, doesn't that raise an exception, halting the request cycle in the worker? 🤔 I wonder if we can simulate such CORS request/response and put it into a test suite.

@timdeschryver
Copy link
Member

I was planning on trying to reproduce this behavior in our test suites today, I'll keep you updated.

timdeschryver added a commit that referenced this issue Jan 23, 2021
@timdeschryver
Copy link
Member

I created a reproduction in our test suite at https://github.com/mswjs/msw/tree/reproduce-529.
I wasn't able to reproduce this via a fetch request, but by adding an image to the page (this is also the case at #529 (comment)).

I still think that we need to handle these responses differently, and current I'm thinking of the following options:

  • don't send the response to the client (my least favorite)
  • send the response to the client, but not with a Response object, but with a custom object
  • send a different response to the client, either with a different object, or without an object since most of the response isn't available

timdeschryver added a commit that referenced this issue Jan 23, 2021
@kettanaito
Copy link
Member

kettanaito commented Jan 24, 2021

I confirm your test suite reproducing the issue reliably, @timdeschryver.

Upon further inspection, I can see that due to the CORS request we get a type: "opaque" response. That is a kind of response that's designed not to contain any information because it's a way to make a CORS request without violating the server's CORS policy (thus mode: "no-cors".

Since such responses cannot be handled in JavaScript per specification, we cannot construct a Response instance out of it to provide to response:bypass life-cycle event. That should be expected by the end developer.

I suggest fixing this by analyzing the response.type and short-circuiting the response listener when we receive an opaque response. I will open a pull request from your branch shortly if you don't mind.

@kettanaito
Copy link
Member

kettanaito commented Jan 24, 2021

Based on the amazing job done by @timdeschryver and other participants of this thread, I've added a pull request (#564) that should fix this issue. MSW will not attempt to construct a Response instance from an opaque response anymore as a part of its life-cycle events. This means you won't get .on('response:bypass') invoked when an opaque response is received. This is the expected and desirable behavior in regards to CORS specification as you cannot manipulate an opaque response in JavaScript by design.

@lwhiteley, I confirm that the aforementioned pull request fixes the issue in your reproduction repository. Once more huge thanks for preparing that!

@Justinohallo
Copy link

Does this mean that v 0.25 will have this update?

I tried npm i msw@latest but am still getting this error.

Delete all node modules as well and reinstalled.

@lwhiteley
Copy link

lwhiteley commented Jan 25, 2021

i assume it will be 0.26 @Justinohallo.

i have downgraded to 0.24 until the change has been released

@timdeschryver
Copy link
Member

@Justinohallo this fix isn't included in v0.25.
It will be in the next released version.

@Justinohallo
Copy link

@lwhiteley @tigerabrodi Thank you!

@kettanaito
Copy link
Member

The fix will be published in the next minor version—0.26.0.

We need to see if we can tackle #536 in the same release, but I'd expect this to be published this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs:reproduction scope:browser Related to MSW running in a browser
Projects
None yet
Development

Successfully merging a pull request may close this issue.