react icon indicating copy to clipboard operation
react copied to clipboard

Cross-origin error passed to componentDidCatch incorrectly

Open bvaughn opened this issue 8 years ago • 58 comments

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 avatar Aug 11 '17 15:08 bvaughn

cc @acdlite, @gaearon, @leidegre

bvaughn avatar Aug 11 '17 15:08 bvaughn

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

gaearon avatar Aug 11 '17 17:08 gaearon

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 avatar Aug 11 '17 19:08 bvaughn

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 avatar Aug 11 '17 19:08 bvaughn

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 avatar Aug 11 '17 20:08 bvaughn

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.

bvaughn avatar Aug 11 '17 21:08 bvaughn

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.

gaearon avatar Aug 11 '17 22:08 gaearon

😭 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.

bvaughn avatar Aug 11 '17 22:08 bvaughn

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.

gaearon avatar Aug 11 '17 22:08 gaearon

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 avatar Aug 11 '17 23:08 bvaughn

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 avatar Aug 11 '17 23:08 bvaughn

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

bvaughn avatar Aug 11 '17 23:08 bvaughn

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

devtool: "eval"

with:

devtool: "cheap-module-source-map"

in your Webpack config.

bvaughn avatar Aug 12 '17 00:08 bvaughn

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.

bvaughn avatar Aug 12 '17 00:08 bvaughn

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

leidegre avatar Aug 12 '17 05:08 leidegre

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

bvaughn avatar Aug 14 '17 21:08 bvaughn

LGTM!

leidegre avatar Aug 15 '17 06:08 leidegre

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:

  • 'Access-Control-Allow-Origin': '*'

sultan99 avatar Oct 15 '17 06:10 sultan99

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.

jjjjw avatar Oct 18 '17 18:10 jjjjw

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.

bvaughn avatar Oct 19 '17 16:10 bvaughn

@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

jjjjw avatar Oct 19 '17 19:10 jjjjw

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.

amertak avatar Oct 23 '17 08:10 amertak

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

thomasdavis avatar Nov 01 '17 04:11 thomasdavis

Can you share a repro, @thomasdavis?

bvaughn avatar Nov 01 '17 15:11 bvaughn

FYI I don't think i reopening this intentionally 😳

jquense avatar Nov 01 '17 15:11 jquense

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

bvaughn avatar Nov 01 '17 15:11 bvaughn

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

jozefpetro avatar Nov 02 '17 15:11 jozefpetro

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>

nick avatar Nov 02 '17 15:11 nick

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

loconluis avatar Nov 05 '17 07:11 loconluis

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?

bvaughn avatar Nov 05 '17 10:11 bvaughn