apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.33k stars 2.65k forks source link

Unsure how to resolve `Missing field while writing result` error when using subscriptions #8677

Open blehoux17 opened 3 years ago

blehoux17 commented 3 years ago

We've implement subscriptions in our application using the useSubscription hook and since upgrading from version 3.3.21 to 3.4.7 we've started to see errors around Missing field.... To be clear we realize these errors have likely always existed, but now they're being surfaced.

We see the following error Missing field 'domainObject' while writing result {} on initial page load when the subscription is registered. We believe that this happens because the first response from the subscription is an empty object. The subscriptions themselves work fine, this only seems to be an issue when they're initially registered. We'd like to resolve this issue and remove the errors from the console, but have so far been unsuccessful.

We tried to update the fetchPolicy and found that setting it to no-cache removed the error, but this stopped the cache from being updated at all, which defeats the purpose.

Shown below is a snippet of the code that we've implemented. Some of the subscriptions allow apollo to do the cache updating on its own (OnObjectUpdated) while with others (OnObjectDeleted) we capture the return data and manually make a change to the cache. In both cases we see the Missing field error. For the OnObjectDeleted subscription, we added a guard in our callback function because when the subscription is registered we receive data as an empty object.

subscription OnObjectDeleted {
  objectDeleted {
    object {
      id
    }
  }
}
const removeObjectFromCache = ({ subscriptionData: { data } }) => {
  if (!data || !data.objectDeleted) return;

  removeObject(data.objectDeleted.object.id, client);
};

useSubscription(OnObjectDeleted, { onSubscriptionData: removeObjectFromCache });
useSubscription(OnObjectUpdated);

We're looking to see if anyone has encountered this and if so how it was resolved.

Thanks!

masterkain commented 3 years ago

yeah I can confirm I have the same issue on initial page subscription, using Vue + ActionCable

subscribeToMore(() => ({
  document: USER_APP_CREATED,
  variables: {
    gravatarSize: 24,
  },
  updateQuery: (oldData, { subscriptionData }) => {
    if (Object.keys(subscriptionData.data).length === 0) {
      return { ...oldData };
    }

stacktrace:

Screenshot 2021-08-30 at 02 09 08
"@apollo/client": "^3.4.8",
"@vue/apollo-composable": "^4.0.0-alpha.14",
"@vue/apollo-util": "^4.0.0-alpha.14",
hsavit1 commented 3 years ago

also having this issue since upgrading from 3.4-beta-0 to 3.4.10

Angulo66 commented 3 years ago

i have the same issue, using "@apollo/client": "^3.3.18" "react-native": "0.64.0",

benjamn commented 3 years ago

@blehoux17 I agree this is not an actionable or useful warning (in this particular case), and we should find a way to hide it.

I'm collecting various subscription-related issues using this label, in case you have any others you think deserve a(nother) look. Hopefully this issue will get fixed in the process, but I've labeled it to be sure.

rebz commented 3 years ago

I too am seeing this error surface after upgrading this morning...

Original versions.

    "@apollo/client": "^3.2.1",
    "@vue/apollo-composable": "^4.0.0-alpha.14",

Upgraded versions.

    "@apollo/client": "^3.4.13",
    "@vue/apollo-composable": "^4.0.0-alpha.15",
mvaivre commented 3 years ago

Also getting this error now (after upgrading) while executing cache.writeQuery (but the cache seems to be properly updated). I'm not using subscriptions.

camilo-perilla-globant commented 3 years ago

Also getting the error using useQuery and MockedProvider

"@apollo/client": "^3.4.13"
Venryx commented 2 years ago

Getting the same issue with apollo-client 3.5.0-beta.4.

Here is the relevant line in the source code, for those wondering: https://github.com/apollographql/apollo-client/blob/212b1e686359a3489b48d7e5d38a256312f81fde/src/cache/inmemory/writeToStore.ts#L327

Not really sure what I'm supposed to do to resolve the issue. (I know one way to solve it is to make sure the server returns a value for every field that Apollo is aware of; however I don't want to have to do that, because the field is already marked as optional in the GraphQL defined on the server, so I want Apollo to be compatible with that without needing server-side workarounds)

EDIT: Found a temporary fix:

apolloClient = new ApolloClient({
    [...]
    cache: new InMemoryCache({
        typePolicies: {
            // temp fix
            MyClass: {
                fields: {
                    missingField1(rawVal: boolean, {args}) { return rawVal ?? null; },
                    missingField2(rawVal: string, {args}) { return rawVal ?? null; },
                },
            },
        },
    }),
});

EDIT2: Nevermind, that seems not to have fixed it -- at least not reliably.

xprazak2 commented 2 years ago

Also getting the error using useQuery and MockedProvider

"@apollo/client": "^3.4.13"

Same.

glekner commented 2 years ago

same

jamesopti commented 2 years ago

Hitting this too since we upgraded to "@apollo/client": "^3.4.9"

KranzAklilu commented 2 years ago

same using "@apollo/client": "^3.3.12"

hatched-danny commented 2 years ago

+1 - "@apollo/client": "^3.4.10"

sahanatroam commented 2 years ago

+1 same

sahanatroam commented 2 years ago

Also getting the error using useQuery and MockedProvider

"@apollo/client": "^3.4.13"

same issue

mheimark commented 2 years ago

Running into this on "@apollo/client": "^3.4.16"

aquelehugo commented 2 years ago

Maybe it helps someone facing that in tests:

It happened with me because a mocked resolver had an exception inside. In my case, I was accessing a property from the first item of an array inside the resolver and the array was empty. The error in the resolver didn't show up, but I had that message from Apollo. When I added a validation for the item existence, the error went away.

fauxparse commented 2 years ago

I think I can make the error go away by making the field optional in my Subscription type:

type Subscription {
  """
  this field shows the error
  """
  joinedSession(sessionId: ID!): JoinedSessionPayload!

  """
  this one doesn't
  """
  leftSession(sessionId: ID!): LeftSessionPayload
}

In my case, I'm using graphql-ruby, so the solution was adding null: true to the field in my SubscriptionType class.

I do still get an onSubscriptionData fire with the initial (empty) payload, but as long as I check that I'm golden.

HTH!

fauxparse commented 2 years ago

I think I can make the error go away by making the field optional in my Subscription type:

Today it is not working 😔

vpaul18 commented 2 years ago

So what's a fix to this problem ? I don't know if you experience the same behaviour, but my subscription doesn't subscribe because of this , which is quite a major problem ....

IShinkarenko commented 2 years ago

The same issue - "@apollo/client": "^3.4.16",

jcook-gresham commented 2 years ago

Also getting the error using useQuery and MockedProvider

"@apollo/client": "^3.4.13"

It seems like there is no ability to have an empty subscription mock, for when we want to only test a Query.

If the subscription isn't included in the mocks prop provided to MockedProvider, I get: No more mocked responses for the query: subscription

If the subscription is included but with no data. something like this:

    {
        request: {
            query: SUBSCRIPTION_,
            variables: {},
        },
        result: {
            data: undefined,
        },
    },

Then Apollo will complain with: Missing field while writing result

Can we get someway of ignoring subscriptions or providing a empty mock, to fix this error?

fvalles commented 2 years ago

Hi everyone! I faced this issue a few weeks ago. In my case, the error was produced by a missing property in a mocked object used by a test. E.g.:

Error:

console.error
    Missing field 'name' while writing result {
      "id": "1",
      "colorHex": "white"
    }

Mocked object:

export const mockedObject: ObjectType = { ...otherProps, category: { colorHex: '#745EA8', id: '11', }, };

In this example, the 'name' property was missing in the mock used by the test, which has a type of:

interface Category {
  id: string;
  name: string;
  colorHex: string;
}

Solution: Make the property optional, or add a mocked value for the mocked object

Oliver-ke commented 2 years ago

Hi everyone still facing this issue after upgrading @apollo/client to 3.5.6,

Missing field 'id' while writing result {
  "property": value,
....

If anyone has a working fix, please kindly share.

efstathiosntonas commented 2 years ago

Not sure if it's the best solution but this eliminated the error:

error is: ExceptionsManager.js:184 Missing field 'chat_channel' while writing result {}

updateQuery: (prev, { subscriptionData }) => {
        if (Object.keys(prev || {}).length === 0) {
          // there's nothing in cache, return empty array otherwise crash!
          return { chat_channel: [] }; <---------- instead of return prev;
        }
vicky-holcomb commented 2 years ago

+1 same

yahuio commented 2 years ago

+1 same "@apollo/client": "^3.3.21",

JDMathew commented 2 years ago

The last working version for me was @apollo/client": "^3.3.11.

This is a real problem as one may not have control over the graphql server they are connecting to.

viveknadig282 commented 2 years ago

Hey guys, the way that I was able to solve this problem was by first checking if the data was there that I was writing. For me, this happened when I was doing cache.writeQuery, and the way I was able to solve it was just by checking if the data existed with an if statement. Hopefully, that helps :)

faerylay commented 2 years ago

Missing field 'me' while writing result {} i have same issue "@apollo/client": "^3.5.8",

TheDutchCoder commented 2 years ago

I can confirm this issue with 3.5.8. Any work being done on this? This seems like it's been reported a long time ago already :(

josnin commented 2 years ago

same "@apollo/client": "^3.5.10",

TheDutchCoder commented 2 years ago

This error only seemed to appear for us when the data returned from the subscription was formatted in a way that Apollo doesn't expect.

Example for an onAccountUpdated subscription:

data {
  id: 1,
  name: 'Kim'
}

This is the way some implementations like apollo-server-lambda return subscription data be default, but it's incorrect, because of two reasons:

  1. It's missing the accountUpdated property wrapper
  2. It's missing the __typename property

We had to manually transform the data returned to subscriptions like this:

data: {
  accountUpdated: {
    __typename: 'Account',
    id: 1,
    name: 'Kim'
  }
}

The underlying issue (for us) is that apollo-server-lambda takes care of subscriptions through a different hander and is not aware of the normal "graph ways" of handling subscriptions and publishes, so the onus is on you to make sure the data is formatted in a "graph way". It's not great, but it seems to work.

Hope it helps other as well!

josnin commented 2 years ago

Thanks @TheDutchCoder make sense,

faerylay commented 2 years ago

guys i can't solve this problem pls help me Missing field 'me' while writing result {} i have same issue "@apollo/client": "^3.5.8",

tintin10q commented 2 years ago

It's been 8 monts and no one that works on apollo has replied? This also happens if mutations have missing fields. Just set them to null they are marked as optionel in the schema

bsonmez commented 2 years ago

I have the same issue with subscriptions

nazrdogan commented 2 years ago

+1

adrielschmitz commented 2 years ago

+1 on v.16.0.1

hannibaldinski commented 2 years ago

+1

olek0012 commented 2 years ago

Maybe it will help someone: i.e. if i have type:

export type Mattertag = Annotation & {
  __typename?: 'Mattertag';
  id: Scalars['ID'];
  created: Scalars['DateTime'];
  modified: Scalars['DateTime'];
  model?: Maybe<Model>;
  floor?: Maybe<ModelFloor>;
  enabled: Scalars['Boolean'];
  color?: Maybe<Scalars['String']>;
  label?: Maybe<Scalars['String']>;
  description?: Maybe<Scalars['String']>;
  media?: Maybe<Scalars['String']>;
  mediaType?: Maybe<MattertagMediaType>;
  anchorPosition?: Maybe<Point>;
  discPosition?: Maybe<Point>;
  stemNormal?: Maybe<Point>;
  stemLength?: Maybe<Scalars['Float']>;
  stemEnabled?: Maybe<Scalars['Boolean']>;
  position?: Maybe<Point>;
  stemDirection?: Maybe<Point>;
};

and in response i had not 'media' and 'mediaType' fields and get this error. Then I added something like this:

cache: new InMemoryCache({
      typePolicies: {
        Mattertag: {
          fields: {
            media: {
              read(media) {
                return media || null;
              },
            },
            mediaType: {
              read(mediaType) {
                return mediaType || null;
              },
            },
          },
        },
      },
    }),

and problem solved temporarily. Waiting for fix

nationalcodecare commented 2 years ago

in my case, before upgrade, I was writing to cache like so: client.cache.writeQuery({ query: cartQuery, data: data.cartCreate.cart })

after upgrade I have to write like this: client.cache.writeQuery({ query: cartQuery, data: data.cartCreate })

and no more error like Missing field 'cart' while writing result

fridaystreet commented 2 years ago

I was getting this ages ago when the error first started appearing and we fixed it by using the cache.modify function inside the update of the mutation with write fragment so apollo isn't expecting all the fields

response = await updateTaskMutation({
  variables,
  optimisticResponse: {
      __typename: 'Mutation',
      updateTask: {
          __typename: 'Task',
          ...data,
          assignee: data.assignee ? { user: { id: data.assignee } } : data.assignee
      }
  },
  update(cache, { data: { updateTask } }) {
      cache.modify({
          fields: {
              taskById(existingData) {
                  const newItem = cache.writeFragment({
                      data: updateTask,
                      fragment: mutations.TASK_DETAILS_RESPONSE
                  });
                  return {
                      ...existingData,
                      task: newItem
                  };
              }
          }
      });
  }
});

in the above taskById is the originally cached call we do to pull the task details from the server when someone opens the task to edit it, before this mutation is run to save it. Apollo automatically ties the ids together inside cache.modify, but you can pass an id if you need to. See https://www.apollographql.com/docs/react/caching/cache-interaction/#using-cachemodify for full documentation.

Anyway, we started using optimistic responses (as you can see above) and the missing field problem came back. When we update we only send the fields that have changed to the server, so the optimistic response is trying to update the cache without all the fields, effectively the same problem as when the actual mutation doesn't return all the fields.

Solution is to ensure the optimistic response also writes the full set of data from the cache, so just ensure whatever you're putting in your optimistic response is a merge of your updated fields and existing cached fields

UPDATE: forgot to mention, not sure if anyone else has seen this, but the reason I went hunting for a solution again is that apollo client was automatically refretching my queries when I had this issue. I thought it was just my code due to rerendering etc, but couldn't stop it happening without solving this error.

I mean this isn't an ideal solution, it really should be handled by apollo client. write.fragment maybe is ok, but the optimistic responses not so much

drewlustro commented 2 years ago

Also experiencing this issue, except for a mutation with an update function passed. The mutation does not select all fields contained in the referenced query.

Thus, when the data gets written to the cache via cache.writeQuery(...), Apollo complains.

KillerCodeMonkey commented 2 years ago

I got the error in the following scenario:

  1. add a custom error handler
  2. on some specific error set response.errors = undefined to suppress bubbling the error
  3. but now the apollo client thinks the query/mutation was successful and tries writing data to the store/cache, but there is none
Oikio commented 2 years ago

In our case solution was straightforward. When response fields were empty backend sent undefined instead of null due to misconfiguration. That lead to an issue with Apollo cache and missing fields error.

jameswahome commented 2 years ago
  updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) return prev;

        const newFeedItem = subscriptionData.data.sortedMessageSubscription;

        const newMessagesCached = {
          sortedMessages: prev.sortedMessages.concat(newFeedItem),
        };

        return Object.assign({}, prev, newMessagesCached);
      },

I solved mine by changing the code as above... where sortedMessages is the name of the field saved in the cache I really hope this helps someone

TheDutchCoder commented 2 years ago

I previously solved this issue here: https://github.com/apollographql/apollo-client/issues/8677#issuecomment-1073004936

But now it has come back because of a subscription that doesn't contain the full object, only updated parts. In our case we have something like:

// Account
{
 id,
 name,
 verified
}

// Data from subscription
{
  id,
  name
}

Apollo, for unknown reasons, complains about verified missing from the response, which makes no sense. I really hope Apollo doesn't expect full DB row dumps on every subscription, that would be hugely wasteful.

It also just appeared a few days ago but I don't remember upgrading anything...

gciluffo commented 2 years ago

This error is super misleading. In our case we had defined schema incorrectly. This error occurred when the actual field we were querying for during runtime didnt match up with the schema. Specifically it had to with returning a string when the type in the graph schema was Url. Changing to String in schema resolved the issue.

csandanov commented 1 year ago

I get this error when I manually update cache via writeQuery.

To clarify the use case for maintainers, I have two types:

type Project {
    id: Int!
    name: String!
}

type App {
    id: Int!
    project: Project!
}

First I fetch projects with all fields:

query projects {
    projects {
        id
        name
    }
}

Then I manually update cache via writeQuery for the following query:

query apps {
    apps {
        id
        project {
            id
        }
    }
}

I'll get Missing field 'name' while writing result error because the nested Project doesn't contain name field. This in turn prevents my cache updates which causes all kinds of new issues.

I hoped I could fix it via typePolicies's merge but the error happens before merge even called. So for now I have to fetch nested types with all fields for my cache writes.

I kiiiinda understand why this is the error (to be explicit about data updates/merge) and not a warning but I would really like to have a global option to make it a warning (or just ignore it completely), so my cache writes would go through and I would still be able to define the behaviour (e.g. use existing value if incoming is missing) in typePolicies's merge.

I have had this issue for a while now and it's still there in 3.7.0