amplify-cli: AWS Amplify GraphQL subscriptions fail with "Cannot return null for non-nullable type: 'AWSDateTime' within parent ... for createdAt/updatedAt"

Describe the bug Subscriptions are triggered correctly by fail to return any data because of null values for automatically created ‘createAt’ and ‘updatedAt’ fields.

To Reproduce

Expected behavior Subscripts get triggered when new items are created but the returned object is null with the following errors:

"message: “Cannot return null for non-nullable type: ‘AWSDateTime’ within parent ‘Video’ (/onCreateVideo/createdAt)” "message: “Cannot return null for non-nullable type: ‘AWSDateTime’ within parent ‘Video’ (/onCreateVideo/updatedAt)”

Code Snippet graphQL schema is as follows - mostly automatically generated by Amplify scripts:

type Video 
@model 
@key(name: "byAlbum", fields: ["albumId"], queryField: "listVideosByAlbum")
@auth(rules: [
  {allow: owner},
  {allow: private, provider: iam}
]) {
    id: ID!
    albumId: ID!
    album: Album @connection(fields: ["albumId"])
    bucket: String!
    fullsize: VideoS3Info!
    thumbnail: VideoS3Info!
}

export const createVideo = /* GraphQL */ `
  mutation CreateVideo(
    $input: CreateVideoInput!
    $condition: ModelVideoConditionInput
  ) {
    createVideo(input: $input, condition: $condition) {
      id
      albumId
      bucket
      fullsize {
        key
        width
        height
      }
      thumbnail {
        key
        width
        height
      }
      createdAt
      updatedAt
      album {
        id
        name
        createdAt
        updatedAt
        owner
        videos {
          nextToken
        }
      }
      owner
    }
  }
`;

export const onCreateVideo = /* GraphQL */ `
  subscription OnCreateVideo($owner: String) {
    onCreateVideo(owner: $owner) {
      id
      albumId
      bucket
      fullsize {
        key
        width
        height
      }
      thumbnail {
        key
        width
        height
      }
      createdAt
      updatedAt
      album {
        id
        name
        createdAt
        updatedAt
        owner
        videos {
          nextToken
        }
      }
      owner
    }
  }
`;

And the React client code

useEffect(() => {
    
    let subscription
    async function setupSubscription() {
      const user = await Auth.currentAuthenticatedUser()
      subscription = API.graphql(graphqlOperation(subscriptions.onCreateVideo, { owner: user.username })).subscribe({
        next: (data) => {
          const video = data.value.data.onCreateVideo
          console.log(data)
          if (video == null) return
          if (video.albumId !== selectedSectionId) return
          setVideos(p => p.concat([video]))
        }
      })
    }

    setupSubscription()

    return () => subscription?.unsubscribe();
  }, [selectedSectionId])

Screenshots image

What is Configured? If applicable, please provide what is configured for Amplify CLI:

  • Which steps did you follow via Amplify CLI when configuring your resources.
  • Which resources do you have configured?
    • If applicable, please provide your aws-exports file:
const awsmobile = {
    "aws_project_region": "ap-southeast-2",
    "aws_cognito_identity_pool_id": "ap-southeast-2:1e784fe9-11d9-48b4-923c-fd1fc92452bb",
    "aws_cognito_region": "ap-southeast-2",
    "aws_user_pools_id": "ap-southeast-2_R1IG6XNDi",
    "aws_user_pools_web_client_id": "7u6ogv91ge55e8f2iuc0lhm0db",
    "oauth": {},
    "aws_mobile_analytics_app_id": "a9bbeba55f2b4c3c830792f3ecabac48",
    "aws_mobile_analytics_app_region": "us-west-2",
    "aws_appsync_graphqlEndpoint": "https://q6xoqjhvvvhnnlawjk42ffaysy.appsync-api.ap-southeast-2.amazonaws.com/graphql",
    "aws_appsync_region": "ap-southeast-2",
    "aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS",
    "aws_user_files_s3_bucket": "rpmappe304a60a89a44621a16622245ad6fb5801950-demo",
    "aws_user_files_s3_bucket_region": "ap-southeast-2"
};
  • If applicable, provide more configuration data, for example for Amazon Cognito, run aws cognito-idp describe-user-pool --user-pool-id us-west-2_xxxxxx (Be sure to remove any sensitive data) N/A
Environment
  System:
    OS: macOS 10.15.7
    CPU: (8) x64 Intel(R) Core(TM) i7-1060NG7 CPU @ 1.20GHz
    Memory: 384.65 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.18.1 - /usr/local/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 6.14.8 - /usr/local/bin/npm
  Browsers:
    Chrome: 85.0.4183.121
    Safari: 14.0
  npmPackages:
    @auth0/auth0-spa-js: ^1.12.1 => 1.12.1 
    @brainhubeu/react-carousel: ^1.19.20 => 1.19.26 
    @date-io/moment: ^1.3.13 => 1.3.13 
    @emotion/core: ^10.0.35 => 10.0.35 
    @emotion/styled: ^10.0.27 => 10.0.27 
    @material-ui/core: ^4.11.0 => 4.11.0 
    @material-ui/icons: ^4.9.1 => 4.9.1 
    @material-ui/lab: ^4.0.0-alpha.56 => 4.0.0-alpha.56 
    @material-ui/pickers: ^3.2.10 => 3.2.10 
    @popperjs/core: ^2.5.2 => 2.5.3 
    @storybook/addon-a11y: ^5.3.19 => 5.3.21 
    @storybook/addon-actions: ^5.3.19 => 5.3.21 
    @storybook/addon-knobs: ^5.3.19 => 5.3.21 
    @storybook/addon-links: ^5.3.19 => 5.3.21 
    @storybook/addons: ^5.3.19 => 5.3.21 
    @storybook/preset-create-react-app: ^3.0.0 => 3.1.4 
    @storybook/react: ^5.3.19 => 5.3.21 
    @storybook/theming: ^5.3.19 => 5.3.21 
    @testing-library/jest-dom: ^5.11.4 => 5.11.4 
    @testing-library/react: ^11.0.4 => 11.0.4 
    @testing-library/user-event: ^12.1.6 => 12.1.6 
    @types/d3-geo: ^1.11.1 => 1.12.1 
    @types/jest: ^26.0.14 => 26.0.14 
    @types/js-cookie: ^2.2.6 => 2.2.6 
    @types/material-ui: ^0.21.8 => 0.21.8 
    @types/node: ^14.11.2 => 14.11.2 
    @types/react: ^16.9.49 => 16.9.50 
    @types/react-color: ^3.0.4 => 3.0.4 
    @types/react-dom: ^16.9.8 => 16.9.8 
    @types/react-redux: ^7.1.9 => 7.1.9 
    @types/react-router-config: ^5.0.1 => 5.0.1 
    @types/react-router-dom: ^5.1.5 => 5.1.5 
    @types/react-simple-maps: ^1.0.3 => 1.0.3 
    @types/react-slick: ^0.23.4 => 0.23.4 
    @types/recharts: ^1.8.13 => 1.8.16 
    @types/styled-components: ^5.1.3 => 5.1.3 
    @types/yup: ^0.29.3 => 0.29.7 
    @typescript-eslint/eslint-plugin: ^4.2.0 => 4.3.0 
    @typescript-eslint/parser: ^4.2.0 => 4.3.0 
    amazon-cognito-identity-js: ^4.4.0 => 4.4.0 
    animate.css: ^4.1.1 => 4.1.1 
    apexcharts: ^3.19.3 => 3.21.0 
    array-move: ^3.0.1 => 3.0.1 
    autoprefixer: ^10.0.0 => 10.0.1 
    autosuggest-highlight: ^3.1.1 => 3.1.1 
    aws-amplify: ^3.3.2 => 3.3.3 
    axios: ^0.20.0 => 0.20.0 
    axios-mock-adapter: ^1.18.2 => 1.18.2 
    babel-eslint: ^10.1.0 => 10.1.0 
    babel-plugin-transform-imports: ^2.0.0 => 2.0.0 
    babel-plugin-transform-remove-console: ^6.9.4 => 6.9.4 
    clsx: ^1.1.1 => 1.1.1 
    connected-react-router: ^6.8.0 => 6.8.0 
    d3-geo: ^2.0.1 => 2.0.1 
    date-fns: ^2.16.1 => 2.16.1 
    downshift: ^6.0.6 => 6.0.6 
    draft-js: ^0.11.7 => 0.11.7 
    eslint: ^6.6.0 => 6.8.0 
    eslint-config-prettier: ^6.12.0 => 6.12.0 
    eslint-config-react-app: ^5.2.1 => 5.2.1 
    eslint-plugin-flowtype: ^5.2.0 => 5.2.0 
    eslint-plugin-import: ^2.22.0 => 2.22.1 
    eslint-plugin-prettier: ^3.1.4 => 3.1.4 
    eslint-plugin-react: ^7.21.2 => 7.21.2 
    eslint-plugin-react-hooks: ^4.1.2 => 4.1.2 
    firebase: ^7.21.1 => 7.22.0 
    flag-icon-css: ^3.5.0 => 3.5.0 
    formik: ^2.1.5 => 2.1.7 
    husky: ^4.2.3 => 4.3.0 
    intl-messageformat: ^9.3.9 => 9.3.9 
    intl-messageformat-parser: ^6.0.7 => 6.0.8 
    jss: ^10.4.0 => 10.4.0 
    jss-extend: ^6.2.0 => 6.2.0 
    jss-rtl: ^0.3.0 => 0.3.0 
    lint-staged: ^10.0.8 => 10.4.0 
    lodash: ^4.17.20 => 4.17.20 
    match-sorter: ^4.2.1 => 4.2.1 
    material-table: ^1.69.0 => 1.69.1 
    material-ui-popup-state: ^1.6.1 => 1.6.1 
    moment: ^2.29.0 => 2.29.0 
    namor: ^2.0.2 => 2.0.2 
    notistack: ^1.0.0 => 1.0.0 
    npm-run-all: ^4.1.5 => 4.1.5 
    postcss-import: ^12.0.1 => 12.0.1 
    prettier: ^2.1.2 => 2.1.2 
    prism-react-renderer: ^1.1.1 => 1.1.1 
    prop-types: ^15.7.2 => 15.7.2 
    purgecss: ^1.4.2 => 1.4.2 
    raw-loader: ^4.0.1 => 4.0.1 
    rc-queue-anim: ^1.8.3 => 1.8.5 
    react: ^16.13.1 => 16.13.1 
    react-apexcharts: ^1.3.7 => 1.3.7 
    react-autosuggest: ^10.0.2 => 10.0.2 
    react-beautiful-dnd: ^13.0.0 => 13.0.0 
    react-big-calendar: ^0.28.0 => 0.28.0 
    react-bottom-scroll-listener: ^4.1.0 => 4.1.0 
    react-chat-window: ^1.2.1 => 1.2.1 
    react-circular-progressbar: ^2.0.3 => 2.0.3 
    react-code-input: ^3.10.0 => 3.10.0 
    react-color: ^2.18.1 => 2.18.1 
    react-daypicker: ^3.0.10 => 3.0.10 
    react-dnd: ^11.1.3 => 11.1.3 
    react-dnd-html5-backend: ^11.1.3 => 11.1.3 
    react-dom: ^16.13.1 => 16.13.1 
    react-draft-wysiwyg: ^1.14.5 => 1.14.5 
    react-draggable: ^4.4.3 => 4.4.3 
    react-dropzone: ^11.2.0 => 11.2.0 
    react-google-maps: ^9.4.5 => 9.4.5 
    react-image-timeline: ^3.2.13 => 3.2.13 
    react-images: ^1.1.7 => 1.1.7 
    react-intl: ^5.8.2 => 5.8.4 
    react-notifications-component: ^2.4.1 => 2.4.1 
    react-number-format: ^4.4.1 => 4.4.1 
    react-perfect-scrollbar: ^1.5.8 => 1.5.8 
    react-photo-gallery: ^8.0.0 => 8.0.0 
    react-player: ^2.6.2 => 2.6.2 
    react-popper: ^2.2.3 => 2.2.3 
    react-redux: ^7.2.1 => 7.2.1 
    react-ripples: ^2.2.1 => 2.2.1 
    react-router-config: ^5.1.1 => 5.1.1 
    react-router-dom: ^5.2.0 => 5.2.0 
    react-router-redux: ^4.0.8 => 4.0.8 
    react-scripts: ^3.4.3 => 3.4.3 
    react-select: ^3.1.0 => 3.1.0 
    react-share: ^4.2.1 => 4.3.0 
    react-simple-maps: ^2.1.2 => 2.1.2 
    react-slick: ^0.27.11 => 0.27.11 
    react-sortable-hoc: ^1.11.0 => 1.11.0 
    react-spring: ^8.0.27 => 8.0.27 
    react-svg-piechart: ^2.4.1 => 2.4.1 
    react-swipeable-views: ^0.13.9 => 0.13.9 
    react-table: 6.10.3 => 6.10.3 
    react-text-mask: ^5.4.3 => 5.4.3 
    react-toastify: ^6.0.8 => 6.0.8 
    react-tooltip: ^4.2.7 => 4.2.10 
    react-transition-group: ^4.4.1 => 4.4.1 
    react-virtualized: ^9.22.2 => 9.22.2 
    react-window: ^1.8.5 => 1.8.5 
    recharts: ^1.8.5 => 1.8.5 
    redux: ^4.0.5 => 4.0.5 
    redux-thunk: ^2.3.0 => 2.3.0 
    slick-carousel: ^1.8.1 => 1.8.1 
    storybook-addon-material-ui: ^0.9.0-alpha.21 => 0.9.0-alpha.21 
    styled-components: ^5.2.0 => 5.2.0 
    tslint: ^6.1.2 => 6.1.3 
    tslint-react: ^5.0.0 => 5.0.0 
    typescript: ^3.8.3 => 3.9.7 
    use-url-search-params: ^2.3.13 => 2.3.13 
    velocity-animate: ^1.5.2 => 1.5.2 
    velocity-react: ^1.4.3 => 1.4.3 
    yup: ^0.29.3 => 0.29.3 
  npmGlobalPackages:
    @aws-amplify/cli: 4.29.4
    amplify-cli: 1.0.0
    npm: 6.14.8
    typescript: 4.0.3
    yarn: 1.22.10

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context N/A

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 6
  • Comments: 34 (5 by maintainers)

Most upvoted comments

I had the similar problem and what I realised is that mutation which in fact triggers the subscription has to have the same response fields as the ones specified for the subscription response. This way it works for me.

I have a very similar issue and spend a complete day trying to figure it out. In a response (I don’t know if here or another place), I figured out that the Subscription will inform you the same response you put in the Create statement.

I was just putting the id in the create statement, and in the Subscription asking some other attributes. Adding all the attributes (or at least the needed by the subscription) corrected my problem.

I hope this comment to save some time for more people

I am getting a similar issue with a connection to a model not allowing me to grab the nested values

type User @model(subscriptions: null) {
  id: ID!
  firstName: String!
  lastName: String!
  email: String!
  messages: [Message] @connection(keyName: "byAuthor", fields: ["id"])
}

type Message @model(subscriptions: null, queries: null) {
  id: ID!
  content: String!
  authorId: ID!
  author: User! @connection(fields: ["authorId"])
  conversationId: ID!
}

type Subscription {
  onCreateMessage(conversationId: ID!): Message @aws_subscribe(mutations: ["createMessage"])
}

and I get the error: "Cannot return null for non-nullable type: 'User' within parent 'Message' (/onCreateMessage/author)"

I’m going to close this issue, as it can be difficult to triage issues that are several years old, and I believe this one has been answered. If you are still having issues, please open a new issue.

For anyone landing here in the future, these are the relevant docs. Particularly this paragraph:

In this case, the subscription selection set must be a subset of the mutation selection set. For example, a subscription addedPost{author title} linked to the mutation addPost(…){id author title url version} receives only the author and title of the post. It does not receive the other fields. However, if the mutation lacked the author in its selection set, the subscriber would get a null value for the author field (or an error in case the author field is defined as required/not-null in the schema).

I hope this can help: Code before modification in file subscriptions.js:

export const onCreateTruckData = /* GraphQL */ subscription OnCreateTruckData($truckId: String!) { onCreateTruckData(truckId: $truckId) { id truckId latitude longitude createdAt updateAt } } ;

Code after modification in file subscriptions.js:

export const onCreateTruckData = /* GraphQL */ subscription OnCreateTruckData($truckId: String!) { onCreateTruckData(truckId: $truckId) { id truckId latitude longitude } } ;

Basically, I erase the fields createAt and updateAt, because this returns null value and does not allow me to access the nested values. In the AWS AppSync Console works without problems, but gave problems when those values were read in my app. With that modification, worked. If I need the time, I think I can get it inside a Lambda function.

Remove the createdAt and updatedAt from the queries.js it solve for me try this

                          `export const getStory = /* GraphQL */ `

query GetStory($id: ID!) { getStory(id: $id) { id title story_type story_text filename createtime // createdAt —>remove this // updatedAt—>remove this } } ; export const listStories = /* GraphQL */ query ListStories( $filter: ModelStoryFilterInput $limit: Int $nextToken: String ) { listStories(filter: $filter, limit: $limit, nextToken: $nextToken) { items { id title story_type story_text filename createtime // createdAt —>remove this // updatedAt—>remove this } nextToken } } ;

In summary, most of the time the behavior reported in this issue is due to the way subscriptions work. If the behavior is different then it is indeed an error.

What @aleksvidak said is kind of expected.

I had the similar problem and what I realised is that mutation which in fact triggers the subscription has to have the same response fields as the ones specified for the subscription response. This way it works for me.

According to the AppSync docs this seems to be the expected behavior.

Subscriptions are triggered from mutations and the mutation selection set is sent to subscribers.

And this part is clearer:

If you use the pure WebSockets client, selection set filtering is done per client, as each client can define its own selection set. In this case, the subscription selection set must be a subset of the mutation selection set. For example, a subscription addedPost{author title} linked to the mutation addPost(…){id author title url version} receives only the author and title of the post. It does not receive the other fields. However, if the mutation lacked the author in its selection set, the subscriber would get a null value for the author field (or an error in case the author field is defined as required/not-null in the schema).

Hope this can help or give a hint to other devs landing at this issue. 😃

I had the similar problem and what I realised is that mutation which in fact triggers the subscription has to have the same response fields as the ones specified for the subscription response. This way it works for me.

I was just trying to figure out the same and it looks like @aleksvidak was correct. It is not an expected behaviour, but works, so thanks 👍

BTW it works correctly if you use amplify mock to test localy 🤷‍♂️

@duncangroenewald what version of Amplify CLI do you have installed?

Could you update your Video type to the following and see if the error goes away

type Video 
@model 
@key(name: "byAlbum", fields: ["albumId"], queryField: "listVideosByAlbum")
@auth(rules: [
  {allow: owner},
  {allow: private, provider: iam}
]) {
    id: ID!
    albumId: ID!
    album: Album @connection(fields: ["albumId"])
    bucket: String!
    fullsize: VideoS3Info!
    thumbnail: VideoS3Info!
    createdAt: AWSDateTime
    updatedAt:AWSDateTime
}

@yuth - sorry for the delayed response been tied down with some other things. I will give that a try and let you know how it goes. Thanks

BTW will these still be auto-populated by AppSync if I defined them in the schema? I guess I’ll find out…