question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Mutations which don't satisfy watched queries cause queries to return no data and no error

See original GitHub issue

Intended outcome:

A mutation which adds data to the store which is insufficient to satisfy an existing query should either return partial data or produce an error. Currently, this snippet exists in readFromStore.js:readStoreResolver:

    if (typeof fieldValue === 'undefined') {
        if (!context.returnPartialData) {
            throw new Error("Can't find field " + storeKeyName + " on object (" + objId + ") " + JSON.stringify(obj, null, 2) + ".");
        }
        context.hasMissingField = true;
        return fieldValue;
    }

Actual outcome:

The above code throws, but is silently caught in QueryManager:getCurrentQueryResult:

            try {
                var data = this.dataStore.getCache().read({
                    query: query,
                    variables: variables,
                    previousResult: lastResult ? lastResult.data : undefined,
                    optimistic: true,
                });
                return maybeDeepFreeze({ data: data, partial: false });
            }
            catch (e) {
                return maybeDeepFreeze({ data: {}, partial: true });
            }

This results in a render which has no usable query data, nor any error.

How to reproduce the issue:

Say you have a classic todo app. A query may contain an array node of actual todos, and renders correctly:

gql`
    query Todos {
        todos {
            id
            text
            details
        }
    }
`;

You then have a mutation to create a todo which only returns the id and text, as we know the details haven’t been filled in yet and we don’t wish to overfetch (or possibly, we just forgot to include the field):

gql`
    mutation addTodo($text: String!) {
        todo {
            id
            text
        }
    }
`;

The original query can no longer be satisfied with what is in the store after this mutation, because a new item has been added which does not include all queried fields. The result is that no query data is returned (ie data.todos is undefined). Additionally, data.error is undefined, and nothing has been reported to the console.

In the real world, we add new products for an order to an array, but the schema has a number of fields which we do not wish to pull back in the mutation result, because we know they will always be null for newly added products. We would prefer to have the flexibility to have these default to null or undefined and let the components dictate behavior there (if we force renderPartialData to true inside the memory cache this works, but that option has been deprecated as a thing we can pass in from our app), but at a minimum, we should be provided with some sort of error so we know why it won’t work. The thrown error is actually rather helpful, but never makes it to the developer.

Version

  • apollo-client@2.2.0

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:9
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
taraponcommented, Oct 31, 2018

This behaviour caused by https://github.com/apollographql/apollo-client/blob/31b0ee4a027c60394cf9297df8f9eeeda3918272/packages/apollo-client/src/core/QueryManager.ts#L994.

I believe error should not be caught. It should be either reported to console or returned to caller as data: { error }.

I’m having hard time debugging it and finding out which field is missing every time

0reactions
hwillsoncommented, May 16, 2019

This has been addressed by https://github.com/apollographql/apollo-client/pull/4743, and will be coming in Apollo Client 2.6. You can set returnPartialData to true to have previous partial cache results used, instead of having the returned data set to an empty object.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mutations in Apollo Client - Apollo GraphQL Docs
If your mutation returns all of the objects and fields that it modified, you can update your cache directly without making any followup...
Read more >
Intro to GraphQL for Beginners [Queries, Types, Mutations ...
In this intro to GraphQL tutorial, Clark Sell gives a crash course on what is GraphQL, why to use GraphQL vs Rest, using...
Read more >
Usage With TypeScript - Redux Toolkit
Result - The type to be returned in the data property for the success case. Unless you expect all queries and mutations to...
Read more >
An Introduction to GraphQL Queries and Mutations
Database queries (and sub-queries) are constructed using a fairly in-depth understanding of the data's structure, types, schema, and model. By ...
Read more >
GraphQL Types, Resolvers, and Operators - MongoDB
The query matches all documents that include the specified field values. If you do not specify a query argument then the mutation replaces...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found