Skip to content

Datastore.save() sending _version of previous query model instead of current model. #13412

@johnmacabed

Description

@johnmacabed

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

DataStore

Amplify Version

v6

Amplify Categories

storage

Backend

Amplify CLI

Environment information

# Put output below this line
System:
    OS: macOS 14.4.1
    CPU: (8) arm64 Apple M1 Pro
    Memory: 84.30 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.16.1 - ~/.nvm/versions/node/v18.16.1/bin/node
    Yarn: 1.22.21 - ~/.nvm/versions/node/v18.16.1/bin/yarn
    npm: 9.5.1 - ~/.nvm/versions/node/v18.16.1/bin/npm
  Browsers:
    Chrome: 124.0.6367.208
    Safari: 17.4.1
  npmPackages:
    @aws-amplify/ui-react: ^6.1.12 => 6.1.12 
    @aws-amplify/ui-react-internal:  undefined ()
    @aws-amplify/ui-react-storage: ^3.1.3 => 3.1.3 
    @aws-sdk/client-s3: ^3.577.0 => 3.577.0 
    @aws-sdk/credential-provider-cognito-identity: ^3.577.0 => 3.577.0 
    @aws-sdk/s3-request-presigner: ^3.577.0 => 3.577.0 
    @fortawesome/fontawesome-free: ^6.5.2 => 6.5.2 
    @fortawesome/fontawesome-svg-core: ^6.5.2 => 6.5.2 
    @fortawesome/free-brands-svg-icons: ^6.5.2 => 6.5.2 
    @fortawesome/free-regular-svg-icons: ^6.5.2 => 6.5.2 
    @fortawesome/free-solid-svg-icons: ^6.5.2 => 6.5.2 
    @fortawesome/react-fontawesome: ^0.2.1 => 0.2.1 
    aos: ^2.3.4 => 2.3.4 
    autoprefixer: ^10.4.19 => 10.4.19 
    aws-amplify: ^6.3.2 => 6.3.2 
    aws-amplify/adapter-core:  undefined ()
    aws-amplify/analytics:  undefined ()
    aws-amplify/analytics/kinesis:  undefined ()
    aws-amplify/analytics/kinesis-firehose:  undefined ()
    aws-amplify/analytics/personalize:  undefined ()
    aws-amplify/analytics/pinpoint:  undefined ()
    aws-amplify/api:  undefined ()
    aws-amplify/api/server:  undefined ()
    aws-amplify/auth:  undefined ()
    aws-amplify/auth/cognito:  undefined ()
    aws-amplify/auth/cognito/server:  undefined ()
    aws-amplify/auth/enable-oauth-listener:  undefined ()
    aws-amplify/auth/server:  undefined ()
    aws-amplify/data:  undefined ()
    aws-amplify/data/server:  undefined ()
    aws-amplify/datastore:  undefined ()
    aws-amplify/in-app-messaging:  undefined ()
    aws-amplify/in-app-messaging/pinpoint:  undefined ()
    aws-amplify/push-notifications:  undefined ()
    aws-amplify/push-notifications/pinpoint:  undefined ()
    aws-amplify/storage:  undefined ()
    aws-amplify/storage/s3:  undefined ()
    aws-amplify/storage/s3/server:  undefined ()
    aws-amplify/storage/server:  undefined ()
    aws-amplify/utils:  undefined ()
    bundle-optimisations:  1.0.0 
    dev-404-page:  1.0.0 
    dotenv: ^16.4.5 => 16.4.5 (7.0.0, 8.6.0, 10.0.0)
    functions:  1.0.0 
    gatsby: ^5.13.5 => 5.13.5 
    gatsby-omni-font-loader: ^2.0.2 => 2.0.2 
    gatsby-plugin-google-analytics: ^5.13.1 => 5.13.1 
    gatsby-plugin-google-gtag: ^5.13.1 => 5.13.1 
    gatsby-plugin-image: ^3.13.1 => 3.13.1 
    gatsby-plugin-manifest: ^5.13.1 => 5.13.1 
    gatsby-plugin-postcss: ^6.13.1 => 6.13.1 
    gatsby-plugin-sharp: ^5.13.1 => 5.13.1 
    gatsby-source-filesystem: ^5.13.1 => 5.13.1 
    gatsby-transformer-sharp: ^5.13.1 => 5.13.1 
    google-map-react: ^2.2.1 => 2.2.1 
    graphql: ^16.8.1 => 16.8.1 (15.8.0)
    internal-data-bridge:  1.0.0 
    load-babel-config:  1.0.0 
    lodash: ^4.17.21 => 4.17.21 
    partytown:  1.0.0 
    postcss: ^8.4.38 => 8.4.38 (7.0.39)
    prettier: ^3.2.5 => 3.2.5 
    prod-404-500:  1.0.0 
    react: ^18.3.1 => 18.3.1 
    react-dom: ^18.3.1 => 18.3.1 
    react-dropdown: ^1.11.0 => 1.11.0 
    react-google-recaptcha-v3: ^1.10.1 => 1.10.1 
    react-headless-accordion: ^1.0.2 => 1.0.2 
    react-scripts: ^5.0.1 => 5.0.1 
    react-table: ^7.8.0 => 7.8.0 
    tailwindcss: ^3.4.3 => 3.4.3 
    webpack-theme-component-shadowing:  1.0.0 
  npmGlobalPackages:
    @typescript-eslint/eslint-plugin: 7.7.0
    corepack: 0.17.0
    gatsby: 5.11.0
    npm-check-updates: 16.14.12
    npm-check: 6.0.1
    npm: 9.5.1
    vite: 5.1.3
    yarn: 1.22.21

Describe the bug

I query my UserLevel model and get the latest data, I update via copyOf then save it. I then do the same with my IndividualData model right after, and its sending the _version that the UserLevel call received in its response. I checked the params before the call and its the correct _version, but the actual call in that gets sent out has the version of the previous model. It will send the right _version if i put a timeout between calls, so it seems to be a race condition. I also went digging in the Datastore lib save function and see awaits in a for loop, awaits are not respected in for loops.

Expected behavior

I expect that my second call to Datastore.save() will have the version that i am sending or calculate it correctly for itself.

Reproduction steps

Call two successive DataStore.save() functions.

Code Snippet

// Put your code below this line.
    const variables = {
      approve: "rejected",
    }

const response = await DataStore.query(UserLevel, id)
const record = await DataStore.save(
  UserLevel.copyOf(response, updated => {
    Object.assign(updated, variables)
  }),
)
const response2 = await DataStore.query(IndividualData, id)
const updateIndividualData = await DataStore.save(
  IndividualData.copyOf(response2, updated => {
    Object.assign(updated, variables)
  })
)

Log output

// Put your logs below this line

{"query":"mutation operation($input: UpdateUserLevelInput!, $condition: ModelUserLevelConditionInput) {\n  updateUserLevel(input: $input, condition: $condition) {\n    id\n    level\n    status\n    owner\n    account\n    reason\n    createdAt\n    updatedAt\n    _version\n    _lastChangedAt\n    _deleted\n  }\n}\n","variables":{"input":{"id":"41cbf570-7011-7058-8347-960a5cda3f7d","level":"0","reason":"First Name Invalid","_version":94},"condition":null}}

{"data":{"updateUserLevel":{"id":"41cbf570-7011-7058-8347-960a5cda3f7d","level":"0","status":false,"owner":"41cbf570-7011-7058-8347-960a5cda3f7d","account":"individual","reason":"First Name Invalid","createdAt":"2024-04-24T16:19:34.312Z","updatedAt":"2024-05-22T17:12:00.349Z","_version":95,"_lastChangedAt":1716397920363,"_deleted":null}}}

{"query":"mutation operation($input: UpdateIndividualDataInput!, $condition: ModelIndividualDataConditionInput) {\n  updateIndividualData(input: $input, condition: $condition) {\n    id\n    approve\n    email\n    firstname\n    lastname\n    nationality\n    country\n    residence\n    poiType\n    type\n    createdAt\n    owner\n    updatedAt\n    _version\n    _lastChangedAt\n    _deleted\n  }\n}\n","variables":{"input":{"id":"41cbf570-7011-7058-8347-960a5cda3f7d","approve":"rejected","_version":95},"condition":null}}

{"data":{"updateIndividualData":null},"errors":[{"path":["updateIndividualData"],"data":null,"errorType":"InvalidVersion","errorInfo":null,"locations":[{"line":2,"column":3,"sourceName":null}],"message":"Client version is greater than the corresponding server version."}]}

Hub Logs from another call, the first gets processed, second fails due to the problem, it enqueues the correct _version, but sends the 102 to server:

Object { event: "outboxMutationEnqueued", data: {…} }
data: Object { model: class Model
, element: {…} }
element: Object { id: "41cbf570-7011-7058-8347-960a5cda3f7d", _version: 101, _lastChangedAt: 1716408811045, … }
_deleted: null
_lastChangedAt: 1716408811045
_version: 101
id: "41cbf570-7011-7058-8347-960a5cda3f7d
reason: ""
name: "UserLevel"

Object { event: "outboxMutationEnqueued", data: {…} }
data: Object { model: class Model
, element: {…} }
element: Object { approve: "approved", id: "41cbf570-7011-7058-8347-960a5cda3f7d", _version: 49, … }
_deleted: null
_lastChangedAt: 1716408811377
_version: 49
approve: "approved"
id: "41cbf570-7011-7058-8347-960a5cda3f7d
name: "IndividualData"

Object { event: "outboxMutationProcessed", data: {…} }
data: Object { model: class Model
, element: {…} }
element: Object { id: "41cbf570-7011-7058-8347-960a5cda3f7d", level: "1", status: false, … }
_deleted: null
_lastChangedAt: 1716408847655
_version: 102
account: "individual"
createdAt: "2024-04-24T16:19:34.312Z"
id: "41cbf570-7011-7058-8347-960a5cda3f7d"
level: "1"
owner: "41cbf570-7011-7058-8347-960a5cda3f7d"
reason: ""
status: false
updatedAt: "2024-05-22T20:14:07.637Z"


//Actual network call params for individual (_version 49)
{"query":"mutation operation($input: UpdateIndividualDataInput!, $condition: ModelIndividualDataConditionInput) {\n  updateIndividualData(input: $input, condition: $condition) {\n    id\n    approve\n    email\n    firstname\n    lastname\n    nationality\n    country\n    residence\n    poiType\n    type\n    createdAt\n    owner\n    updatedAt\n    _version\n    _lastChangedAt\n    _deleted\n  }\n}\n","variables":{"input":{"id":"41cbf570-7011-7058-8347-960a5cda3f7d","approve":"approved","_version":102},"condition":null}}

[WARN] 14:07.870 DataStore 
Object { recoverySuggestion: "Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues", localModel: {…}, message: "Client version is greater than the corresponding server version.", operation: "Update", errorType: "Unknown", errorInfo: null, process: "mutate", cause: {…}, remoteModel: null }

if i put a timeout of 500ms between them it works fine.

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

After finding #7354, I am suspecting the _version in the previous requests response overwrites the mutation in the outbox because it has the same id as the previous request, even though its another model and different request. If this is the case, I will have to prevent multiple requests with same id parameter.
No response

Metadata

Metadata

Labels

DataStoreRelated to DataStore categorybugSomething isn't workingpending-maintainer-responseIssue is pending a response from the Amplify team.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions