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
What is Configured?
If applicable, please provide what is configured for Amplify CLI:
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"
};
aws cognito-idp describe-user-pool --user-pool-id us-west-2_xxxxxx
(Be sure to remove any sensitive data)
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):
Additional context
N/A
@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
}
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)"
@LoganArnett It looks like your schema expect the author to be non-nullable, and the Message
does not seem to have an valid author. This could either be because the createMessage
passed an non-existent authorId
or the Author with that authorId
was delete from User
table.
I am not sure what happened but I edited another model and pushed and it worked so maybe somehow I was out of sync, thanks @yuth
Please feel free to comment here if you need any further clarification
@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 awaytype 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...
@yuth - I just tried that but the returned object is still null.
If I turn AppSync logging on I should be able to see the error in CloudWatch right?
Hmm nothing to see in CloudWatch!
But no errors reported now in the browser console.
Amplify 4.29.8
Could you try running the subscription and mutation in the AppSync console. This should make it easier to debug as you can narrow down if the problem is in AppSync resolver or in the Javascript side of things
BTW will these still be auto-populated by AppSync if I defined them in the schema? I guess I'll find out...
It should add the autopupulate createdAt
and updatedAt
if no value was passed in the input
This subscription seems to work fine in the console:
subscription MySubscription {
onCreateVideo {
id
bucket
key
sessionDate
isReviewed
reviewedBy
reviewDate
title
comments
sessionTypeID
activityTypeID
modeID
genderID
ageGroupID
weightCategoryID
athletes {
items {
id
createdAt
updatedAt
}
nextToken
}
createdAt
updatedAt
sessionType {
id
name
activityTypes {
nextToken
}
modes {
nextToken
}
createdAt
updatedAt
videos {
nextToken
}
}
owner
}
}
However the definition is slightly different to the one used in the app which has the $owner parameter - and I am not sure I understand the distinction. I an going to try a customised subscription without the $owner parameter in the app.
export const onCreateVideo = /* GraphQL */ `
subscription OnCreateVideo($owner: String) {
onCreateVideo(owner: $owner) {
id
bucket
key
sessionDate
isReviewed
reviewedBy
reviewDate
title
comments
sessionTypeID
activityTypeID
modeID
genderID
ageGroupID
weightCategoryID
athletes {
items {
id
createdAt
updatedAt
}
nextToken
}
createdAt
updatedAt
sessionType {
id
name
activityTypes {
nextToken
}
modes {
nextToken
}
createdAt
updatedAt
videos {
nextToken
}
}
owner
}
}
`;
So in the end I got rid of the $owner in the schema definition - which fixed the problem. I guess it wasn't happy that I was not passing in the owner parameter so couldn't send the data but could still trigger the event.
I'm having a similar issue with subscriptions. However, it isn't working in the AppSync console either.
This is the error:
"data": {
"onUpdateLead": null
},
"errors": [
{
"message": "Cannot return null for non-nullable type: 'String' within parent 'Lead' (/onUpdateLead/formId)",
"path": [
"onUpdateLead",
"formId"
]
},
{
"message": "Cannot return null for non-nullable type: 'DeliveryStatus' within parent 'Lead' (/onUpdateLead/deliveryStatus)",
"path": [
"onUpdateLead",
"deliveryStatus"
]
}
]
These is the error I get in my app when a subscription returns. Also, just like in the AppSync console message no object is being returned.
0: Object { message: "Cannot return null for non-nullable type: 'String' within parent 'Lead' (/onUpdateLead/formId)", path: (2) […] }
1: Object { message: "Cannot return null for non-nullable type: 'String' within parent 'Lead' (/onUpdateLead/pageId)", path: (2) […] }
2: Object { message: "Cannot return null for non-nullable type: 'Status' within parent 'Lead' (/onUpdateLead/status)", path: (2) […] }
3: Object { message: "Cannot return null for non-nullable type: 'DeliveryStatus' within parent 'Lead' (/onUpdateLead/deliveryStatus)", path: (2) […] }
4: Object { message: "Cannot return null for non-nullable type: 'ID' within parent 'Lead' (/onUpdateLead/mappingDataID)", path: (2) […]
5: Object { message: "Cannot return null for non-nullable type: 'AWSDateTime' within parent 'Lead' (/onUpdateLead/createdAt)", path: (2) […]
6: Object { message: "Cannot return null for non-nullable type: 'AWSDateTime' within parent 'Lead' (/onUpdateLead/updatedAt)", path: (2) […] }
If I don't include any of the non-nullable fields in the return of the subscription the ID returns but any other field returns null. Why is that?
Schema
type Lead
@model
@key(name: "byMappingData", fields: ["mappingDataID"])
@auth(
rules: [
{ allow: private, operations: [update, read] }
{ allow: private, provider: iam, operations: [create, read, update] }
]
) {
id: ID!
formId: String!
pageId: String!
processedLeadData: String
status: Status!
deliveryStatus: DeliveryStatus!
zohoResponse: String
createdTime: String
fbLeadId: String
rawLeadData: [FieldData]
mappingDataID: ID!
submitDataToZoho: Boolean
mappingData: MappingData @connection(fields: ["mappingDataID"])
}
This is the subscription I'm using:
export const onUpdateLead = /* GraphQL */ `
subscription OnUpdateLead {
onUpdateLead {
id
formId
pageId
processedLeadData
status
deliveryStatus
zohoResponse
createdTime
fbLeadId
rawLeadData {
name
values
}
mappingDataID
submitDataToZoho
createdAt
updatedAt
mappingData {
id
formName
formId
pageId
mappingInfo {
forcedFields
}
rawLeadFields {
key
label
type
id
conditional_questions_group_id
}
status
formCreatedTime
deliveryStatus
errors
campaignName
campaignId
archived
createdAt
updatedAt
leads {
nextToken
}
}
}
}
`;
When I use the updateLead mutation it returns whatever fields are selected to be returned. I don't understand why the subscription isn't doing this. Am I missing something?
I'm using 4.30.0 of the Amplify CLI.
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've run into this issue and have tried 10 different ways to solve it. my object returned was:
type Checkin
@model
@searchable
@key(name: "byUserId", fields: ["userId"], queryField: "checkinByUserId")
@auth(
rules: [
{ allow: owner }
{ allow: private, operations: [read] }
{ allow: private, provider: iam, operations: [create, read, update] }
]
) {
comment: String
createdAt: AWSDateTime!
time: AWSDateTime!
id: ID!
userId: ID!
team: Team @connection(name: "CheckinOnTeam")
game: Game! @connection(name: "CheckinsOnGame")
updatedAt: AWSDateTime!
user: User! @connection(name: "CheckinOnUser")
venue: Venue @connection(name: "CheckinOnVenue")
isPrivate: Boolean
atHome: Boolean
}
and I have a mutation:
updateCheckinStats(
action: String!
checkinId: String!
numCheers: Int
numComments: Int
): Checkin! @function(name: "updateCheckinStats-${env}")
When I run the query in the api console it still get:
Cannot return null for non-nullable type: 'Game' within parent 'Checkin' (/updateCheckinStats/game)
Cannot return null for non-nullable type: 'User' within parent 'Checkin' (/updateCheckinStats/user)
I've punted on it and just having it return boolean if the update was successful but this is super annoying.
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 🤷♂️
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.
This worked for me as well.... So strange...
Most helpful comment
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.