facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
228.55k stars 46.78k forks source link

Cross-origin error passed to componentDidCatch incorrectly #10441

Open bvaughn opened 7 years ago

bvaughn commented 7 years ago

tl;dr React is passing "A cross-origin error was thrown" to componentDidCatch when there are no cross-origin scripts.

See this discussion thread and this repro case.

I was able to confirm the behavior. A quick look at onError showed a null event.error.

bvaughn commented 7 years ago

cc @acdlite, @gaearon, @leidegre

gaearon commented 7 years ago

Could be something funky caused by e.g. eval?

bvaughn commented 7 years ago

Not sure I understand. Are you asking if the user-code is maybe using eval?

The repro is just accessing a prop on a null value.

bvaughn commented 7 years ago

Looks like the repro case (starting with the tessin_mini repo) can be reduced to:

import React, { Component } from "react";

export default class App extends Component {
  state = {
    doError: false,
  };

  render() {
    return (
      <ErrorBoundary>
        {this.state.doError
          ? <ComponentThatFails/>
          : <button onClick={() => this.setState({doError: true})}>Click me</button>}
      </ErrorBoundary>
    )
  }
}

class ErrorBoundary extends Component {
  state = {
    error: null
  };

  componentDidCatch(error) {
    this.setState({error})
  }

  render() {
    if (this.state.error) {
      return this.state.error.message;
    }
    return this.props.children
  }
}

class ComponentThatFails extends Component {
  render() {
    const data = null;
    return <p>{data.foo}</p>;
  }
}

The console will log:

Uncaught TypeError: Cannot read property 'foo' of null

But the error we pass to componentDidCatch will be:

A cross-origin error was thrown...

bvaughn commented 7 years ago

I think this has something to do with the bundling code in the tessin_mini repo. The same code in a CRA-created app works as expected.

Maybe it has to do with the SSR logic?

bvaughn commented 7 years ago

Creating a small, standalone project with no SSR/Webpack/etc, I am able to reproduce the unexpected behavior only for Chrome when loading content via file://....

Here's what I'm seeing:

Browser standalone file:// standalone http:// tessin_mini dev tessin_mini prod
Chrome 1 2
Firefox
Safari

1: I believe Chrome considers files loaded with file:// to always be a different domain. If I launch Chrome with the --allow-file-access-from-files flag, the standalone file works with when loaded via the file:// protocol as well.

2: Also worth adding that the tessin_mini example works as expected in production mode (b'c we use a regular try/catch). The unexpected cross-origin error only affects dev-mode.

gaearon commented 7 years ago

By eval I meant the Webpack devtool: "eval" setting which is commonly used and turns every module into eval call so that it's shown separately in DevTools despite no sourcemaps. But seems like we determined that isn't the issue.

bvaughn commented 7 years ago

😭 Thanks for clarifying!

You're absolutely right. That was the cause. Removing that property from the Webpack config clears the issue up in the tessin_mini project.

gaearon commented 7 years ago

We can probably encourage people to stop using it and use cheap-module-source-map instead. It's just as fast (afaik) and doesn't have some issues.

bvaughn commented 7 years ago

It's interesting that I use the devtool: "eval" setting in react-virtualized's Webpack config also but it doesn't show this error.

I'm not super familiar with Webpack. 😄

Edit This was working for the RV project b'c of redbox-react + react-transform-catch-errors.

bvaughn commented 7 years ago

For what it's worth, I ran through the all of the devtools settings and here's what I found:

devtool works?
default
eval
cheap-eval-source-map
cheap-source-map
cheap-module-eval-source-map
cheap-module-source-map
eval-source-map
source-map
inline-source-map
hidden-source-map
nosources-source-map

It looks like the default setting (and any of the *eval ones) will cause problems.

bvaughn commented 7 years ago

I'll put up a PR that adds addition verbiage to the cross-origin (dev-mode) error to mention this.

bvaughn commented 7 years ago

FYI @leidegre the solution for this issue is to replace:

devtool: "eval"

with:

devtool: "cheap-module-source-map"

in your Webpack config.

bvaughn commented 7 years ago

The team chatted out of band about this briefly and the agreed-upon solution is to change the wording of the error message passed to componentDidCatch to be:

A cross-origin error was thrown so React doesn't have access to the actual error object in development. See https://fb.me/react-crossorigin-error for more details.

At the specified URL we'll have a blurb that explains the technique we're using in dev-mode and mentions both the <script> tag crossorigin attribute for CDNs and the Webpack devtools setting.

leidegre commented 7 years ago

@bvaughn @gaearon So I'm just super happy that we could root cause this, thanks for the hard work! Enjoy your weekend!

bvaughn commented 7 years ago

You're welcome @leidegre!

Just to close the loop here, we've added a new docs page with information about this and other cross-origin error causes:

https://fb.me/react-crossorigin-error

leidegre commented 7 years ago

LGTM!

sultan99 commented 7 years ago

The problem A cross-origin error was thrown. React doesn't have access to the actual error object in development. comes with react v16 in development mode as soon as I switch it to the production mode it works fine.

No one of these helped:

jjjjw commented 7 years ago

I ran into this problem when using webpack, code splitting, and webpack dev server (similar to a CDN setup).

In my setup the initial bundle is loaded with a script tag, and other bundles are then loaded via JSONP by webpack. With the crossorigin attribute added to the script tag for the initial bundle errors can be handled, but only if they are thrown by code in the initial bundle.

To handle errors in the other bundles it's necessary to configure webpack for crossorigin script loading with this option https://webpack.js.org/configuration/output/#output-crossoriginloading

Like so in the webpack config:

  ...  
  output: {
    crossOriginLoading: 'anonymous',
    ...
  }

This adds the crossorigin attribute to the JSONP script tags used to load the bundles.

bvaughn commented 7 years ago

Hey @jjjjw. Thanks for the additional info!

Any chance you could point me to a minimal repro/setup of the setup you're describing? I'd like to better understand it so that I can update the cross-origin-errors page in the React docs.

jjjjw commented 7 years ago

@bvaughn

Sure, here is a simple demo project: https://github.com/jjjjw/crossorigin-webpack-demo

Worth noting that the case is when webpack dev server is used on a different port/domain than the web server.

Additionally, here is a first go at a doc addition: https://github.com/reactjs/reactjs.org/pull/187

amertak commented 7 years ago

I am experiencing the same issue. Webpack is running on different domain than the whole application. It is being wired together using the nginx. The only way to see the error for me is to start chrome with --disable-web-security flag I actually have no idea if its even possible to fix it.

thomasdavis commented 6 years ago

I'm also having no luck, using crossorigin attr, CORS enabled and using cheap-module-source-maps

bvaughn commented 6 years ago

Can you share a repro, @thomasdavis?

jquense commented 6 years ago

FYI I don't think i reopening this intentionally 😳

bvaughn commented 6 years ago

No worries. If people are still seeing it, it's probably okay to re-open it. 😄

jozefpetro commented 6 years ago

Same problem here, tried both crossOriginLoading: 'anonymous' and devtool set to 'cheap-module-eval-source-map'

nick commented 6 years ago

I had to do these 3 things together (using webpack-dev-server running on port 8080):

Add this to webpack config:

devServer: {
    headers: {
        'Access-Control-Allow-Origin': '*'
    }
}

use cheap-module-source-map (cheap-module-eval-source-map did not work)

Add crossorigin to my script tag:

<script crossorigin src="http://localhost:8080/public/bundle.js"></script>
loconluis commented 6 years ago

I am using cheap-module-source-map, but the error is thrown twice. Does anyone know what it could be?

bvaughn commented 6 years ago

I am using cheap-module-source-map, but the error is thrown twice. Does anyone know what it could be?

What makes you say the error is thrown twice?

Are you referring to what Dan describes in facebook/react/issues/10384, by chance?

herodrigues commented 6 years ago

Same happening here using cheap-module-source-map, using webpack and an ErrorBoundary component. It only happens when I don't set NODE_ENV to production, which does not make any sense since I want to run in development mode.

bvaughn commented 6 years ago

It only happens when I don't set NODE_ENV to production, which does not make any sense since I want to run in development mode.

Are you also referring to what Dan describes in facebook/react#10384, by chance?

herodrigues commented 6 years ago

@bvaughn yeah, I've read the whole discussion in your previous comment and the answer is 'kind of'.

So, basically I shouldn't set NODE_ENV to development in my React app, because component errors should be thrown only production, right?

bvaughn commented 6 years ago

So, basically I shouldn't set NODE_ENV to development in my React app

You shouldn't set NODE_ENV to "development" for your production app because this will result in your app getting the slower, development build of react. The development build of React includes many helpful warnings. While useful in development, they make React larger and slower so you don't want to use them in production.

because component errors should be thrown only production, right?

Errors can occur in development or production modes. The duplicate console logging only happens in development mode though, for reasons Dan mentioned in the issue I linked to.

herodrigues commented 6 years ago

Thanks @bvaughn, but my case is a bit more complex.

I didn't set NODE_ENV to "development" in my app either in production or development mode. I'm just trying to see those helpful warnings during development. However, my app only works if I set NODE_ENV to 'production' even when I want to use development mode (as stated in here)

bvaughn commented 6 years ago

However, my app only works if I set NODE_ENV to 'production' even when I want to use development mode (as stated in here)

If I'm understanding this correctly, I don't know why this would be. Maybe related to another dependency your project has? Either way, sounds like a separate issue from the component stack stuff 😄 Maybe file it separately, with more details?

herodrigues commented 6 years ago

@bvaughn that's what I'm looking for. My app is inside a Chrome extension, which is an odd environment for React.

If it's something related to React and Chrome extensions and not an specific issue with my project, I'll create a separate issue with maybe a tutorial on how to solve it.

Thanks!

bvaughn commented 6 years ago

My app is inside a Chrome extension, which is an odd environment for React.

Sounds similar to react-devtools 😄

herodrigues commented 6 years ago

@bvaughn, my project is buggy. Sorry for flooding this thread. To whom it may concern, here's a minimal setup of a Chrome extension using React, Redux, react-devtools and error boundaries.

Source: https://github.com/herodrigues/chrome-react-minimal

ezgif com-crop

DominikSerafin commented 6 years ago

Same issue here with Windows 10, Chrome 62, Webpack 3 & React 16.0-16.1.

Webpack+React always throws Error: A cross-origin error was thrown. React doesn't have access to the actual error object in development..


Tried devtool: 'cheap-module-source-map' (and others without eval)


Tried

devServer: {
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
      "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
    },
}

Tried

output: {
  crossOriginLoading: 'anonymous',
}

Tried crossorigin script tag


Nothing works

StalkAlex commented 6 years ago

Experiencing same problem in Chrome, nothing works as @DominikSerafin mentioned, but there is no such error in Firefox.

edongashi commented 6 years ago

Getting same behavior as two previous comments in chrome.

the-spyke commented 6 years ago

Updated dependencies today and started to get this issue in tests. Not sure what is just as fast, but in my project eval is 2-3 times faster in rebuilds by webpack-dev-server watch.

DominikSerafin commented 6 years ago

Same thing for me as for @the-spyke, eval is much faster than other alternatives in my project(s).

React should work correctly with it, and not suggest workarounds (which do not even work).

Hoping it will get fixed...

sapegin commented 6 years ago

I’ve noticed that I have this issue when Chrome DevTools are open, crossOriginLoading and devtool = cheap-module-source-map doesn’t change anything. Works fine in Firefox with open developer tools.

evelant commented 6 years ago

I'm still getting this as well no matter my webpack settings.

IanVS commented 6 years ago

@herodrigues were you able to get valid errors in your chrome extension in dev? I have a chrome extension as well and am seeing the same cross-origin errors.

BrendonSled commented 6 years ago

Try checking your package.json, remove the -d flag.

That's what finally worked for me.

DominikSerafin commented 6 years ago

@BrendonSled

Do you mean the npm loglevel flag? https://docs.npmjs.com/misc/config#shorthands-and-other-cli-niceties

If yes, then it isn't a fix, but just merely "silencing" the problem, so I wouldn't recommend doing this because you might silence other useful errors this way.

herodrigues commented 6 years ago

@IanVS there was something wrong in my project. I developed a "clean" extension using React and everything is ok.

See my comment https://github.com/facebook/react/issues/10441#issuecomment-343282447