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

State empty when SSR fails because of getDataFromTree throws #1403

Closed
gabriel-miranda opened this issue Dec 12, 2017 · 15 comments
Closed

State empty when SSR fails because of getDataFromTree throws #1403

gabriel-miranda opened this issue Dec 12, 2017 · 15 comments

Comments

@gabriel-miranda
Copy link

Intended outcome:
SSR query fails and fills the field loading with: false, error with: <error> and the <keys> you wanted with their respective values. And doesn't run again on client side.

Actual outcome:
SSR query fails and fills the field loading with: true, error with: undefined and the <keys> you wanted with undefined.

How to reproduce the issue:
You can reproduce it here: https://github.com/gabriel-miranda/chorus/tree/develop querying a post that doesnt exist, or doing a query that fails in any server with SSR (next.js example also).
This happens because when you do:

    try {
          // Run all GraphQL queries
          await getDataFromTree(
            <ApolloProvider client={apollo}>
              <ComposedComponent url={url} {...composedInitialProps} />
            </ApolloProvider>
          );
        } catch (error) {
          // Prevent Apollo Client GraphQL errors from crashing SSR.
          // Handle them in components via the data.error prop:
          // http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error
        }

File reference: https://github.com/gabriel-miranda/chorus/blob/develop/src/www/utils/withData.js

getDataFromTree throws an error and doesn't fill the apollo state needed.

Version

  • apollo-client@2.0.4
  • react-apollo@2.0.4
@gabriel-miranda
Copy link
Author

gabriel-miranda commented Jan 2, 2018

Any updates on this? Should I send a PR fixing this after I find out the best solution?
The issue is here:

throw error;

This breaks entirely SSR

@flippidippi
Copy link

flippidippi commented Feb 12, 2018

What's even weirder, if you are using the next.js with-apollo example and upgrade to the latest preset, if the GraphQL server returns an error status code (like 400), the try catch does successfully catch the getDataFromTree successfully, but somehow the error is thrown later, after the try catch and the render, causing a crash :/

@dejayc
Copy link

dejayc commented Mar 4, 2018

@flipxfx have you tried using getDataFromTree().catch(/* your callback goes here. */)

@flippidippi
Copy link

I using try { await getDataFromTree(...) } catch (error) {}. It catches the error there, but then throws it again somewhere along the way.

@dejayc
Copy link

dejayc commented Mar 9, 2018

I using try { await getDataFromTree(...) } catch (error) {}. It catches the error there, but then throws it again somewhere along the way.

Maybe use a try/catch block within the catch callback to figure out what's happening.

@flippidippi
Copy link

Well now I can't reproduce it. I've updated quite a bit on our Apollo server and client since then so not sure what was happening.

@richardscarrott
Copy link

richardscarrott commented Nov 6, 2018

@gabriel-miranda did you find a solution to this? Currently the only solution I can see is to handle errors differently on the server vs client, e.g.

const ProductDetailPage = () => {
    <Query query={PRODUCT_DETAIL_PAGE}>
        {({ loading, error, data }) => {
            if (loading) return 'loading...';
            // Errors are handled here, but only for the client render
            if (error) return <Status code={error.code}>{error.code === 404 ? 'Not found' : 'Server error}</Status>; 
            if (data) return <Product {...data.product} /> 
            return null;
        }}
    </Query>
}

const serverRenderer = async (req, res) => {
    const routerContext = {};
    const root = ...;
    try {
        await getDataFromTree(root);
    } catch(error) {
        // Errors have to be handled here for the server render (which a) is a different code path to the client and b) is not component specific)
        res.status(error.code).send(renderToString(<Status code={error.code}>{error.code === 404 ? 'Not found' : 'Server error}>);
        return;
    }
    const html = renderToString(root);
    res.status(routerContext.status).send(html);
}

@sombreroEnPuntas
Copy link

I get a similar issue when using renderToStringWithData.
Ended up with a similar workaround to just print the error:

    res.status(500)
    res.end(
      `An error occurred with the following stack trace:\n\n${error.stack}`
    )

@sombreroEnPuntas
Copy link

It is related to this one as well:
#1972

@hwillson
Copy link
Member

getDataFromTree has been re-written since this issue was created, so please try out a current day version of react-apollo and let us know if this problem is still happening. Thanks!

@EyMaddis
Copy link

EyMaddis commented Sep 13, 2019

@hwillson This is still an issue with the latest version.
I use

    "@apollo/react-hooks": "3.1.0",
    "@apollo/react-ssr": "3.1.0",
    "apollo": "2.18.1",
    "apollo-cache-inmemory": "1.6.3",
    "apollo-client": "2.6.4",
    "apollo-link-http": "1.5.16",

Here is an example. We want to get the current user name and handle the case that the user is not logged in (which results in a GraphQl error):

const CurrentUserQuery = gql`
  query CurrentUser {
    currentUser {
      name
    }
  }
`

function useCurrentUser() {
  return useQuery(CurrentUserQuery, {
    ssr: true,
    errorPolicy: 'none', // 'all' somewhat helps, at least the end result is the same, but I want the error object!
  })
}


function ApolloTest(props) {
  const { data, loading, error } = useCurrentUser()

  if (error) {
    return <BaseText>ERROR: {error.message}</BaseText>
  }

  return (
    <BaseText>
      {loading ? 'LOADING...' : (data && JSON.stringify(data)) || 'NO DATA'}
    </BaseText>
  )
}

The server returns "LOADING...." while the client will show the error message after hydration.
The server throws the following exception:
Error while running `getDataFromTree` { Error: GraphQL error: Not logged in at new ApolloError (./node_modules/apollo-client/bundle.umd.js:92:26)

I think this is a duplicate of apollographql/apollo-client#3897

@EyMaddis
Copy link

EyMaddis commented Feb 20, 2020

@hwillson This is still an issue, even with 4.0.0!
Even worse, after getDataFromTree handled an error once, every following SSR request will break. This is only fixed by restarting the server!
It seems that there is an unintended side effect during SSR rendering which persists between queries.

I tested with Next.js 9.2.1:
Throw an error on page 1,
open another page 2 (directly in the browser, meaning via SSR) which uses Apollo and the page will return as if the page would be loading (I disabled JS). However when the client runs it has a fully filled cache and renders as if the page was successfully loaded.
Because of the way Reacts hydration works, this can lead to the weirdest rendering! For me a big banner at the top is cut in half after SSR because CSS styles get applied to the wrong elements.


    "@apollo/client": "3.0.0-beta.34",
    "@apollo/react-ssr": "4.0.0-beta.1",
   "apollo-cache-inmemory": "^1.6.3",
    "apollo-link-http": "^1.5.16",
    "apollo-link-retry": "^2.2.15",

@eviL-ivan
Copy link

any ideas?

@maapteh
Copy link
Contributor

maapteh commented Mar 23, 2020

@hwillson we are having the same issue. When an SSR throws an error it will throw the error on our page level and have to restart the server. I see getDataFromTree is rewritten (but not catching) and we are using version 3 latest.

how to proceed? The error will not be in the return, the app will just break

When errorPolicy is set to all it will not throw it during treewalker, but error is not getting passed to component.

Created reproduction on codesandbox in the issue mentioned below #3918

@emhagman
Copy link

emhagman commented Apr 14, 2020

Same issue. We have authenticated queries that are allowed to fail which return loading: false, error: ... when they do. getDataFromTree will fail if the user is not logged but keeps the loading set to true for the query even though the query has failed, preventing our logic from displaying the proper UI.

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

10 participants