React-apollo: All Errors Catched

Created on 20 May 2016  Â·  23Comments  Â·  Source: apollographql/react-apollo

When using the connect method from react-apollo, all errors that occur in one of the child components, are catched by apollo and fail silently.

Development gets nearly impossible then.

Any ideas why that could be the case?
Using apollo-client 0.3.5 and react-apollo 0.3.3

Thanks!

bug

Most helpful comment

I am on 1.0.0-rc.5 of both react-apollo and apollo-client and am still seeing this issue :(

Any render error causes apollo's query data to not appear, the error itself is swallowed.

All 23 comments

@johnthepink didn't you run into this case as well?

@timsuchanek do you have some code I can use to replicate and write a test? Where is the child component failing and what is react-apollo doing?

As soon as I can replicate I'll fix ASAP!

For instance:

  it('doesn\'t catch all errors of children ', () => {
    const store = createStore(() => ({ }));
    const query = gql`
      query people {
        allPeople(first: 1) {
          people {
            name
          }
        }
      }
    `;

    const data = {
      allPeople: {
        people: [
          {
            name: 'Luke Skywalker',
          },
        ],
      },
    };

    const networkInterface = mockNetworkInterface({
      request: { query },
      result: { data },
    });

    const client = new ApolloClient({
      networkInterface,
    });

    const mapQueriesToProps = () => ({
      errorTest: {
        query,
      },
    });

    let fail: any;

    class ErrorChild2 extends React.Component<any, any> {
      render(){
        return (
          <div>
            {(() => {
              return fail.test.foobar;
            })()}
            <Passthrough {...this.props} />;
          </div>
        )
      }
    }

    class ErrorChild1 extends React.Component<any, any> {
      render(){
        return fail.test.foobar;;
      }
    }

    @connect({ mapQueriesToProps })
    class Container1 extends React.Component<any, any> {
      render() {
        return <ErrorChild1 {...this.props} />;
      }
    };

    @connect({ mapQueriesToProps })
    class Container2 extends React.Component<any, any> {
      render() {
        return <ErrorChild2 {...this.props} />;
      }
    };

    const mountMethod1 = () => {
      return mount(
        <ProviderMock store={store} client={client}>
          <Container1 pass='through' baz={50} />
        </ProviderMock>
      );
    }

    const mountMethod2 = () => {
      return mount(
        <ProviderMock store={store} client={client}>
          <Container2 pass='through' baz={50} />
        </ProviderMock>
      );
    }

    expect(mountMethod1).to.throw;
    expect(mountMethod2).to.throw;

  });

Correctly passes? So two different error types both throw correctly

Hmm of course when I try to create a minimal example, also all errors throw correctly.

So I am using this boilerplate: https://github.com/graphcool-examples/react-apollo-todo-example

Probably some other side effects are involved in interfering the proper error propagation.

My conclusion was that the problem should be react-apollo when I substituted the connect method with the one from react-redux. Then all errors threw again correctly.

As soon as I have a reproducible example, I'll post it here

@timsuchanek I have been running in to this issue as well. I'll do some digging.

@timsuchanek would you be willing to share the class that isn't throwing errors in your app?

@timsuchanek it looks like our issue didn't have to do with react-apollo, but with react's error reporting directly. In certain cases, React swallows exceptions and doesn't report them.

Here is the open issue on the react repo https://github.com/facebook/react/issues/2461

For our project, I added react-transform-catch-errors, and altered our babel settings, and now we have the errors that you would expect on components using connect and the children of those components.

I know you mentioned you were using that boilerplate. It doesn't look like it includes a way to deal with catching the errors in react lifecycle functions. So maybe that will help?

Hey guys, thanks for the input so far!
I still can't figure out a reproducible example, but this is my quick fix, using it in the render() method of my connect'ed component:

    if (this.props.data.errors) {
      console.error(this.props.data.errors.stack);
    }

Here is a repro that should help. See the Readme for details. I've never put something like this together before so any feedback is appreciated.

https://github.com/jlevycpa/apollo-error-repro

I updated to the latest version of react-apollo but I'm still seeing this issue. When I update the reproduction I posted above, the behavior changes slightly. The behavior of an error in the Item component is now the same as the behavior in the Container component - an error in the apollo store and no error in the console. The cryptic console error Cannot read property 'replaceChild' of null seems to be gone.

@jbaxleyiii did you try running the reproduction with the update? Did you have different results? Maybe I didn't update correctly or something?

still not fixed

Is it possible that this line is the problem? It looks like the rendered child is getting stored instead of being returned directly. I'm wondering if that is breaking the call stack instead of letting the error bubble all the way up through the return calls in the render methods. If I have time I will test this theory.

It looks like the reason for storing the rendered child is to prevent re-renders. But isn't that what ShouldComponentUpdate is for?

@jbaxleyiii not sure if you have already started on this bug, but I believe the test here has a logic bug in it: https://github.com/apollostack/react-apollo/blob/master/test/client/connect/queries.tsx#L1965

count gets incremented to 1 the first time render gets hit with data.loading set to true
count gets incremented to 2 the second time render gets hit with data.loading set to false. It then hits that line in the code and the test passes, never actually hitting the key line in https://github.com/apollostack/react-apollo/blob/master/test/client/connect/queries.tsx#L1970.

Fixing that alone doesn't make the test a correct reproducible test, but it's a start.

I still have this bug in latest version of Apollo. Using it together with redux.

networkError: "Error: Attempted to update component `SourceItem` that has already been unmounted (or failed to mount)"

It's not a network error.

Update: It happens only if I use Apollo's reducer and middleware with redux. Without connecting it to my redux store I can see errors, but they are all caught in apollo-client/store.js.

Store.js:13 Caught an exception! ReferenceError: test is not defined(…)

@jbaxleyiii Why this issue is closed?

@skuridin looks like this was a bug in apollo client that was reintroduced. I believe a fix is already in place for it in the next release. react-apollo as the issue point was refactored and fixed to correctly error. Including tests added to prevent this regression

@jbaxleyiii does this still happen with 0.5.4? I'm not aware of any bug having been reintroduced.

Is there any official docs about error handling in mutations?

I've found one way — mutate(..).catch(err => alert(err));

I am on 1.0.0-rc.5 of both react-apollo and apollo-client and am still seeing this issue :(

Any render error causes apollo's query data to not appear, the error itself is swallowed.

please help me; where use throw in this code:

const SignInWithData = graphql(signInMutation)(withRouter(SignInFormContainer));


const mapDispatchToProps = dispatch => ({
  signInDispatcher(token) {
    dispatch(signIn(token));
  },
});

const SignInWithDataAndState = connect(
  null,
  mapDispatchToProps,
)(SignInWithData);

export default SignInWithDataAndState;

Was this page helpful?
0 / 5 - 0 ratings