"Cannot return null for non-nullable field" error

I have an Item custom class, and I use a custom graphql mutation to update an item via a resolver in Cloud code so that I can do some other middleware things at the same time.

# custom schema.graphql
extend type Mutation {
  editItem(input: UpdateItemInput!): UpdateItemPayload @resolve
}
// graphql playground
mutation {
  editItem(
    input: {
      id: "gKTdECrXci"
      fields: {
	    title: "New title"
      }
    }
  ) {
    item {
      title
    }
  }
}

Invoking the mutation results in this error:
"message": "Cannot return null for non-nullable field UpdateItemPayload.item."

Adding UpdateItemPayload (from Parse’s generated schema) to my custom schema does not change things:

# custom schema.graphql
type UpdateItemPayload {
  # This is the updated object.
  item: Item!
  clientMutationId: String
}

However, if instead I short-circuit things and don’t use UpdateItemPayload at all, my mutation work fine, and the item is updated correctly:

# custom schema.graphql
extend type Mutation {
  editItem(input: UpdateItemInput!): Item! @resolve
}
// graphql playground
mutation {
  editItem(
    input: {
      id: "gKTdECrXci"
      fields: {
	    title: "New title"
      }
    }
  ) {
    title
  }
}

How can I get past this and be able to use UpdateItemPayload? I would like my custom mutation format to match what Parse is using.

Could you share the cloud code that you are using to resolve this mutation?

Sure…I’ve distilled it down a bit for use here, but it still throws the error.

Parse.Cloud.define('editItem', async (req) => {
  const { params: { input: { id, fields } } } = req;
  const itemQuery = new Parse.Query('Item');
  const item = await itemQuery.get(id);
  return item.save({ ...fields });
});

You probably need something like this:

Parse.Cloud.define('editItem', async (req) => {
  const { params: { input: { id, fields } } } = req;
  const itemQuery = new Parse.Query('Item');
  const item = await itemQuery.get(id);
  return { item: item.save({ ...fields }) };
});

Copy that! Thank you. I didn’t realize that UpdateItemPayload wouldn’t “build” the data structure to be returned for me on its own.

The actual solution is slightly different because I have to await item.save() so it should be:

return { item: await item.save({ ...fields }) };

Or something with a bit less code smell than dumping an await in the middle of the object. It’s all working now. Thanks again!

You do not need to await item save since GraphQL will await it for you normally.

Lol, you’re right, of course. Brain fade.