Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Unhandled Network Error #604

Closed
maxtechera opened this issue Apr 6, 2017 · 80 comments
Closed

Unhandled Network Error #604

maxtechera opened this issue Apr 6, 2017 · 80 comments

Comments

@maxtechera
Copy link

Steps to Reproduce

Describe how to reproduce this issue.

  1. Being offline or using an invalid url
  2. Start your app

Buggy Behavior

Unhandled promise rejection stops the execution of the app.

Expected Behavior

Component should render without data and errors received through props. The same when its a query error or some kind of http error.

Version

@lyquocnam
Copy link

may this relate ?
#599

@helfer
Copy link
Contributor

helfer commented Apr 7, 2017

@maxtechera thanks! Could you provide more information, like a stack trace or a reproduction using react-apollo-error-template? That would help us fix the issue faster.

@carobeta
Copy link

carobeta commented Apr 7, 2017

I have the same issue when the url is invalid.

screen shot 2017-04-07 at 3 42 53 pm

@jbaxleyiii
Copy link
Contributor

Closing since this has been longer than 2 weeks without a reproduction. If it is still an issue, feel free to reopen!

@zackify
Copy link

zackify commented May 30, 2017

This happens for me too. All you have to do is kill your graphql server and try running a query in react native. It will throw an unhandled error. I was trying to mimic the server being down and see how I was supposed to handle errors. Not sure how this isn't an issue for others?

@ghost
Copy link

ghost commented May 31, 2017

Yeah same for me ! I have absolutely no idea how to handle down server. When I open my app in Airplane mode it's just crashing...

@zackify
Copy link

zackify commented Jun 1, 2017

How are we supposed to catch exceptions from this? Any ideas @jbaxleyiii

@jbaxleyiii jbaxleyiii reopened this Jun 1, 2017
@OscarYuen
Copy link

Same for me. In my case, I attach a jwt token in header for apollo client. Whenever the jwt token is expired, server side return error json with status equal to 401, and I got 'Unhandled (in react-apollo)', 'ApolloError .

@saadbinsaeed
Copy link

saadbinsaeed commented Jun 8, 2017

I solved this by handling exception on main page where the apollo-query has been executed.

if(this.props.data.error)
  return <ErrorComponent /> ;

@zackify
Copy link

zackify commented Jun 8, 2017

This is horribly repetitious. I don't want to have to do that. I want to catch all these in my top level component and throw up an alert view, otherwise every render method I have to do this. Or make a higher order component in front of the component making the query.

@sabativi
Copy link

sabativi commented Jun 8, 2017

Hello,

Here is a repo to reproduce the error https://github.com/sabativi/apollo-offline-network-error
I use https://mpjk0plp9.lp.gql.zone/graphql as graphql url

Also to look at the problem here is a video record : http://recordit.co/DrPPhE4Fof.

Hope it will help @helfer

@sabativi
Copy link

Hey, I had posted a repo to reproduce more than one week ago and still do not have any feedback.
Did i miss something ?

@amensouissi
Copy link

Hello,
I have a same problem

@helfer
Copy link
Contributor

helfer commented Jun 17, 2017

Hi @sabativi sorry I didn't respond earlier, I don't always have time to check issues every day.

Thanks a lot for the reproduction, it helped me quickly figure out what is going on. In essence, refetch works a little bit differently from other queries, and it's up to you to explicitly handle errors. That means you should change your code from simply refetch() to refetch().catch(e => { /* handle error here */). If you don't want to handle the error, you can use catch( e => null).

Here's a complete example:

class App extends Component {
  render() {
    const { data: { refetch, loading, hero, error } } = this.props;
    if(loading) {
      return (<p>Loading…</p>);
    }
    return (
      <main>
        <header>
          <h1>Apollo Client Error Template</h1>
          <p>{error && error.message}</p>
          <h3>{!error && hero.name}</h3>
          <button onClick={() => refetch().catch(e => null)}>
            Refetch
          </button>
        </header>
      </main>
    );
  }
}

I hope it helps! 🙂

PS: I'm happy to discuss changing this behavior in a future major version of the API, but for the time being we have to keep it because it would be a breaking change to remove it.

@helfer helfer closed this as completed Jun 17, 2017
@zackify
Copy link

zackify commented Jun 21, 2017

@helfer This still is not a solution to the problem. In my render method, if I do this:

let { vaults, refetch } = this.props.data;

And an error occurs, a big red box shows up saying unhandled network error. If I simply change it to destructure and pull out the error, it works:

let { vaults, refetch, error } = this.props.data;

This is pointless, because either way, I have after middleware catching all errors at the network interface level. Apollo should not be telling me the exception is uncaught when I am logging it in the network interface middleware. As I mentioned earlier, myself and many others do not want to add error handling on every component. Without this being fixed, we have to manually check for an error inside every component that makes a query.

@nenti
Copy link

nenti commented Jun 22, 2017

@helfer You stated, that one needs to handle the error when it should not be thrown. Is there a possibility to do so when using the react-apollo graphql(query).catch(?!) object?

Because one can't catch on the component.

@sabativi
Copy link

Indeed this is the problem I was trying to show by using a refetch when offline, but obviously was not a good choice...

@nisimjoseph
Copy link

same here. the call works in GraphiQL but not using react-apollo & apollo-client.

anyone know how to solve it?

@ghost
Copy link

ghost commented Jul 5, 2017

Hi, has this problem been solved?
I'm wondering the same thing as @nenti .

All my containers are wrapped in graphql(query)(component) and call the query everytime they're rendered.
Is there a way to catch these Network error?
@helfer

@helfer
Copy link
Contributor

helfer commented Jul 6, 2017

Hey @vincentpageau, I'll let @jbaxleyiii give you the authoritative answer on that, but I believe the way to "handle" the error when using the graphql HOC is to simply check data.errors inside the component. There's a check inside apollo-client that throws if data.errors isn't accessed.

@zackify
Copy link

zackify commented Jul 6, 2017

@helfer I would love to get rid of that check! Haha

@ghost
Copy link

ghost commented Jul 6, 2017

@helfer @jbaxleyiii So basically when the loading value switches to false, check if data.error has a value?
Would it

  • catch the error?
  • crash before it enters the if(data.error) { ... } loop
  • enter the loop and still crash?

I'm using this at the moment and the Network error still crashes my app:

const {error, loading} = this.props.data;

    if (loading) {
      return null;
    }else if (error) {
      return (
        <div className='ComponentDistance'>
          <Translate value='application.error_message' />
          {error}
        </div>
      );
    } else {
    return <div> ... </div>
    }

Thank you for your patience^

@Amnesthesia
Copy link

Jesus, is there no way around this?

@koenpunt
Copy link
Contributor

I don't think Jesus is among us

@gastonmorixe
Copy link

gastonmorixe commented Apr 12, 2018

Setting error policies on the client solved it for me.

const apolloClient = new ApolloClient({
 ...
  defaultOptions: {
    watchQuery: {
      errorPolicy: 'none'
    },
    query: {
      errorPolicy: 'none'
    },
    mutate: {
      errorPolicy: 'none'
    }
  }
})

@Amnesthesia
Copy link

Thank you @gastonmorixe, I'm gonna try that out — setting it on each query, even if accessing this.props.data.errors, did nothing at all on ReactNative, and still kept crashing with a red screen. This throwing is kind of a nightmare on React Native right now

@gastonmorixe
Copy link

@Amnesthesia I am with you there, it is hell on RN. Good luck.

conrad-vanl added a commit to NewSpring/Apollos that referenced this issue Apr 13, 2018
* downgrade apollo to circumvent bug

Running into this issue:
apollographql/apollo-client#3236

* Fix network error catching

apollographql/react-apollo#604 (comment)
5648596

* fix refetch/fetchmore handlers when null

* make sure errors are passed through on nested HOCs

* improve error handling on profile

* fix linter

* update snapshots

* add audio error handling
@diegocouto
Copy link

Hey @mjasnikovs 👋, were you able to properly catch 401 exceptions? I'm already accessing props.data and catching errors from .refetch(), but errors keep being thrown... 😓

@melloflavio
Copy link

@diegocouto I ran on a similar issue while using apollo-link. Where I would try catching an error by all means and was still getting the red screen. The root cause was a sort of uncatchable error that was being raised.

Take a look at this issue: apollographql/apollo-link#542, might help you in some way...

@mjasnikovs
Copy link

@diegocouto Hi, enjoy this pain. Apollo products like trowing errors randomly by design. So enjoy this ride.

I made this weird looking component. It is working for me. :/

import React from 'react'
import PropTypes from 'prop-types'
import {Message} from 'semantic-ui-react'

const Errors = ({errors}) => {
	if (!errors) {
		return null
	} else if (Array.isArray(errors.graphQLErrors) && errors.graphQLErrors.length) {
		return <Message negative>
			<Message.Header>Kļūda</Message.Header>
			<p>{errors.graphQLErrors.map(val => val.message).join(<br />)}</p>
		</Message>
	} else if (errors.message) {
		return <Message negative>
			<Message.Header>Kļūda</Message.Header>
			<p>{errors.message}</p>
		</Message>
	}
	return null
}

Errors.propTypes = {
	errors: PropTypes.oneOfType([PropTypes.object, PropTypes.bool])
}

export default Errors

Then

<Query query={DRAWINGS_CATS_Q}>
  {queryState => {
    if (queryState.error) {
      return <Errors errors={queryState.error} />
    }

@MrLoh
Copy link
Contributor

MrLoh commented May 17, 2018

@gastonmorixe @Amnesthesia @jbaxleyiii What is the solution to stop this error in react native, even when accessing the error and console.logging it is still being thrown globally. I can't catch it with componentDidCatch either nor does an errorLink help.

I respect that the opinion is that errors should be handled explicitly, but this is not documented and the solution is unclear and it crashes React Native apps easily, something should be done about this. At least a proper documentation, or better an option to switch it off via a flag in the client.

@MrLoh
Copy link
Contributor

MrLoh commented May 17, 2018

Do I have to switch to the new Query component to prevent this @pennyandsean ? I'm still using graphql and would like to keep it that way, I guess I could easily build my own graphql HOC.

@MrLoh
Copy link
Contributor

MrLoh commented May 17, 2018

Seems that replacing the graphql component by a custom HOC that uses Query under the hood, solved the issue. This urgently needs better documentation though. I'd write some, but I'm not sure I understand how network errors are actually handled.

@immortalx
Copy link

In react native using the Query component i only have this error when doing a refetch or fetchMore. If it's just the normal query, it handles everything fine.

I tried all the solutions excluding using a HOC, nothing worked for refetch or fetchMore.

@pennyandsean
Copy link

@MrLoh, in the end I could still make it fail with the render props, just not as often. My project is react native so it was particularly visible, however in the codesandbox sample, it helps to open up the console to see the exceptions. Looking at the code, both APIs wrap the basic query so you could roll your own. Must admit I haven't tried it with the basic client.query yet.

@pennyandsean
Copy link

pennyandsean commented May 23, 2018

It seems to come from here is that helps anyone. I could be wrong but maybe @stubailo was that your baby? Perhaps refetch and fetchMore need to be brought under the errorPolicy?

@nacho-carnicero
Copy link

I'm having the same issue here, no way of catching the network errors with Apollo. Every time I switch off the internet connection I get the red screen error no matter which solution I try. @MrLoh can you share the HOC you created? I'd love to test if it works for me too.

@vjsingh
Copy link

vjsingh commented Jun 28, 2018

+1. I'm not getting a red screen, but even after accessing props.data.error in a component wrapped in the HOC component 'graphql' I'm getting a "Possible Unhandled Promise Rejection: Error: Network error: Network request failed" in React Native

@rankun203
Copy link

rankun203 commented Aug 2, 2018

@404sand808s I'm also looking for a easier way to retry (all kinds of) operation, did you found any?

@404sand808s
Copy link

@rankun203 sadly no, not yet.

@rankun203
Copy link

rankun203 commented Aug 2, 2018

An irrelevant comment has been moved to stack overflow.

@MrLoh
Copy link
Contributor

MrLoh commented Aug 4, 2018

@rankun203 this seems to have nothing to do with this issue. Please don’t pollute issues with random related questions, but use stack overflow.

@rankun203
Copy link

@MrLoh That's reasonable, sorry for putting wrong discussions here.

@mrdulin
Copy link

mrdulin commented Aug 16, 2018

My issue is when I navigate to a route, at this moment token expired, my graphql server will throw an 'Unauthorized' error.

At apollo client, with apollo-link-error, the error will be caught. But it will broadcast to current component with graphql() enhancer. The app will crash.

It does't make sense that handle the global error(Unauthorized) in local (in Component)

I want to intercept the error and stop mount react component.

function errorHandler({ graphQLErrors, networkError }) {
    if (graphQLErrors) {
      graphQLErrors.map(error => {
        if (error.code === 1001) {
          auth.signout();
          window.location.replace('#/login');
          //TODO: stop here!! Don't mount component and navigate to '#/login' route
        }
      });
    }

    if (networkError) {
      if (networkError.statusCode === 401) {
        auth.signout();
        window.location.replace('#/login');
      }
    }
  }

@farzd
Copy link

farzd commented Sep 18, 2018

So if you're offline, component blows up in ReactNative, it does latch the error to the error prop afterwards. My setup is pretty default, using apollo-link-error as well

image

@immortalx i remember reading that if you're refetch is failing then you need to latch on catch at the end of that refetch().catch((e) => {});

edit: Turned out deconstructing was the issue, oops.

<Error style={styles.errorStyles} {...error} />

@509dave16
Copy link

There is another solution that involves accessing the error for any query/mutation by wrapping the graphql decorator/function. I don't guarantee this solution to be perfect. But this is what I came up with when we couldn't move to a newer version of react-apollo:

export const graphql = (document, operationOptions) => {
  const origHof = origGraphql(document, operationOptions)
  return (WrappedComponent) => {
    const CustomGraphqlWrapper = (props) => {
      let handler = null
      if (
        (!operationOptions || !(handler = props[operationOptions.name])) // if named handler not defined continue checking
        && !(handler = props.data) // if unamed query handler not defined keep checking
        && !(handler = props.mutate) // if unamed mutation handler not defined then we know not try accessing an error
      ) {
        return origHof // we aren't decorating the wrapped component with a handler, so no error needs accessing
      }
      if (handler.error) {
        console.log('GraphQL Request Error', handler.error)
      }
      return <>
        <WrappedComponent {...props} />
      </>
    }
    return origHof(CustomGraphqlWrapper)
  }
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests