Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gen 2 Client Update fails (Cannot destructure property 'isReadOnly' of 'fields[fieldName]' as it is undefined) #3059

Open
MKlaeui opened this issue Dec 8, 2024 · 6 comments
Assignees
Labels
bug Something isn't working data-schema Gen 2

Comments

@MKlaeui
Copy link

MKlaeui commented Dec 8, 2024

Environment information

System:
  OS: Linux 6.6 Debian GNU/Linux 12 (bookworm) 12 (bookworm)
  CPU: (8) x64 AMD Ryzen 3 7320C with Radeon Graphics
  Memory: 3.36 GB / 6.38 GB
  Shell: /bin/bash
Binaries:
  Node: 20.10.0 - ~/.config/nvm/versions/node/v20.10.0/bin/node
  Yarn: 1.22.21 - ~/.config/nvm/versions/node/v20.10.0/bin/yarn
  npm: 10.9.2 - ~/.config/nvm/versions/node/v20.10.0/bin/npm
  pnpm: 8.15.1 - ~/.config/nvm/versions/node/v20.10.0/bin/pnpm
NPM Packages:
  @aws-amplify/auth-construct: 1.5.0
  @aws-amplify/backend: 1.8.0
  @aws-amplify/backend-auth: 1.4.1
  @aws-amplify/backend-cli: 1.4.2
  @aws-amplify/backend-data: 1.2.1
  @aws-amplify/backend-deployer: 1.1.10
  @aws-amplify/backend-function: 1.8.0
  @aws-amplify/backend-output-schemas: 1.4.0
  @aws-amplify/backend-output-storage: 1.1.3
  @aws-amplify/backend-secret: 1.1.5
  @aws-amplify/backend-storage: 1.2.3
  @aws-amplify/cli-core: 1.2.0
  @aws-amplify/client-config: 1.5.2
  @aws-amplify/deployed-backend-client: 1.4.2
  @aws-amplify/form-generator: 1.0.3
  @aws-amplify/model-generator: 1.0.9
  @aws-amplify/platform-core: 1.2.2
  @aws-amplify/plugin-types: 1.5.0
  @aws-amplify/sandbox: 1.2.6
  @aws-amplify/schema-generator: 1.2.5
  aws-amplify: 6.10.2
  aws-cdk: 2.172.0
  aws-cdk-lib: 2.172.0
  typescript: 5.7.2
No AWS environment variables
No CDK environment variables

Data packages

├─┬ @aws-amplify/[email protected]
│ └─┬ @aws-amplify/[email protected]
│   └── @aws-amplify/[email protected]
└─┬ @aws-amplify/[email protected]
  └─┬ @aws-amplify/[email protected]
    └── @aws-amplify/[email protected]

Description

I have an Next SSR project. Whenever I try to use the client update function, I get a type error (Cannot destructure property 'isReadOnly' of 'fields[fieldName]' as it is undefined.)

image

// page.tsx
'use client';

import { generateClient } from 'aws-amplify/data';
import { type FC, useEffect, useState } from 'react';

import type { Schema } from '@/amplify/data/resource';
import '@aws-amplify/ui-react/styles.css';
import './app.css';
import { Amplify } from 'aws-amplify';

const client = generateClient<Schema>();


const HomePage: FC = () => {
    const [sites, setSites] = useState<Schema['Site']['type'][]>([]);

    useEffect(() => {
        const listSites = client.models.Site.observeQuery().subscribe({
            // eslint-disable-next-line no-unused-vars
            next: ({ items, isSynced }) => {
                console.log('subscribe listen to change: ', items);
                setSites([...items]);
            },
        });
        return () => listSites.unsubscribe();
    }, []);

    async function createSite() {
        const { errors, data } = await client.models.Site.create({
            name: window.prompt('Site title') ?? 'You entered nothing.',
            displayName: 'Whatever you want',
        });
        if (data) {
            console.log('A new site was created: ' + data.name);
        } else if (errors) {
            console.log('Errors occured while creating a site', errors);
        }
    }

    async function updateSite(idx: number) {
        const name = window.prompt('Site name') ?? 'You entered nothing.';
        const record = { ...sites[idx], name };
        const conf = Amplify.getConfig();
        console.log('Just before', conf);
        const { errors, data } = await client.models.Site.update(record);
        if (data) {
            console.log('The site update was successful: ' + data.name);
        } else if (errors) {
            console.log('Errors occured while updating a site', errors);
        }
    }

    return (
        <div>
            <button onClick={createSite}>+ new</button>
            <ul>
                {sites.map((site, index) => (
                    <li onClick={() => updateSite(index)} key={site.id}>
                        {site.name}
                    </li>
                ))}
            </ul>
            <div>
                🥳 App successfully hosted. Try creating a new site.
                <br />
                <a href="https://docs.amplify.aws/nextjs/start/quickstart/nextjs-app-router-client-components/">
                    Review next steps of this tutorial.
                </a>
            </div>
        </div>
    );
};

export default HomePage;
// resource.ts

import { type ClientSchema, a, defineData } from '@aws-amplify/backend';

/*== STEP 1 ===============================================================
The section below creates a Todo database table with a "content" field. Try
adding a new "isDone" field as a boolean. The authorization rule below
specifies that any user authenticated via an API key can "create", "read",
"update", and "delete" any "Todo" records.
=========================================================================*/
const schema = a.schema({
    ExperienceEnum: a.enum(['Great', 'Ok', 'Mediocre', 'Lousy']),
    AlphabetEnum: a.enum(['A', 'B', 'C', 'D']),
    Address: a.customType({
        street: a.string(),
        city: a.string(),
    }),
    CustomerDetails: a.customType({
        address: a.ref('Address'),
        since: a.datetime().required(),
    }),
    Verbiage: a.customType({
        name: a.ref('AlphabetEnum').required(),
        paragraphs: a.string().required().array().required(),
    }),
    Part: a
        .model({
            name: a.string().required(),
            orders: a.hasMany('CustomerPart', 'partId'),
        })
        .authorization(allow => [allow.owner()]),
    Customer: a
        .model({
            name: a.string().required(),
            // verbiage: a.ref('Verbiage').required().array().required(),
            verbiage: a.ref('Verbiage').required().array(), // .required(),
            orders: a.hasMany('CustomerPart', 'customerId'),
        })
        .authorization(allow => [allow.owner()]),
    CustomerPart: a
        .model({
            customerDetails: a.ref('CustomerDetails'),
            experience: a.ref('ExperienceEnum'),
            customer: a.belongsTo('Customer', 'customerId'),
            customerId: a.string(),
            part: a.belongsTo('Part', 'partId'),
            partId: a.string(),
        })
        .authorization(allow => [allow.owner()]),

    Site: a
        .model({
            name: a.string().required(),
            displayName: a.string().required(), // title
        })
        .authorization(allow => [
            allow.guest().to(['read']),
            allow.owner().to(['read']),
            allow.authenticated().to(['read', 'create', 'update', 'delete']),
            allow.group('Admin').to(['read', 'create', 'update', 'delete']),
        ]),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
    schema,
    authorizationModes: {
        defaultAuthorizationMode: 'userPool',
        // apiKeyAuthorizationMode: {
        //     expiresInDays: 30,
        // },
    },
});
@chrisbonifacio
Copy link
Member

Hi @MKlaeui thanks for raising this issue! 👋 This is probably a configuration related issue.

I see that you are calling Amplify.getConfig(); just before the client.models.Site.update() call.

Can you share what the config looks like? There should be a model introspection schema in it.

Also, please confirm that the sandbox is running and updating the amplify_outputs.json file.

@chrisbonifacio chrisbonifacio added the pending-community-response Issue is pending a response from the author or community. label Dec 16, 2024
@chrisbonifacio chrisbonifacio self-assigned this Dec 16, 2024
@chrisbonifacio chrisbonifacio added question Further information is requested and removed pending-triage labels Dec 16, 2024
@MKlaeui
Copy link
Author

MKlaeui commented Dec 17, 2024

I appreciate you looking into this. Sandbox is running and it generated the amplify_outputs.json file. Attached the results of the getConfig call. Let me know if I didn't expand the objects you are looking for. Thanks!
Screenshot 2024-12-17 5 17 55 PM
Screenshot 2024-12-17 5 17 38 PM
Screenshot 2024-12-17 5 15 27 PM
Screenshot 2024-12-17 5 15 08 PM

@github-actions github-actions bot added pending-maintainer-response Issue is pending a response from the Amplify team. and removed pending-community-response Issue is pending a response from the author or community. labels Dec 17, 2024
@chrisbonifacio
Copy link
Member

chrisbonifacio commented Dec 17, 2024

@MKlaeui Thank you for the MIS! Unfortunately, there isn't anything that stands out about the MIS.
We might need more information. For instance, we noticed that your client side code to update a Site is constructing a record from an existing site and replacing the name. Would you be able to console log that record so we can match it against the schema?

const record = { ...sites[idx], name };
console.log({record}) // add this console log

Lastly, could you also share how you're configuring the Amplify library? (ex. calling Amplify.configure). Usually the reason why this error would occur is because of a drift between the MIS and the backend schema, causing fields to not be present in the MIS.

@chrisbonifacio chrisbonifacio added pending-community-response Issue is pending a response from the author or community. and removed pending-maintainer-response Issue is pending a response from the Amplify team. labels Dec 17, 2024
@MKlaeui
Copy link
Author

MKlaeui commented Dec 18, 2024

Attached is the log of the record. I'm not sure this will help, but I suspected it may have something to do with this being a Next App Router project, so I created it as a plain React/Vite project. However, I got a similar error, the only difference being that it said fields7[fieldname]. I'm also attaching that. Thanks!

Calling Amplify.configure in Layout like so:

'use client';

import './globals.css';
import { Authenticator } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';
import { Amplify } from 'aws-amplify';
import config from '@/amplify_outputs.json';

import type { PropsWithChildren } from 'react';

Amplify.configure(config, { ssr: true });

Screenshot 2024-12-18 3 29 54 PM
Screenshot 2024-12-18 3 42 06 PM

@github-actions github-actions bot added pending-maintainer-response Issue is pending a response from the Amplify team. and removed pending-community-response Issue is pending a response from the author or community. labels Dec 18, 2024
@chrisbonifacio
Copy link
Member

chrisbonifacio commented Dec 19, 2024

Hi @MKlaeui!

So, I was able to reproduce the error with the given shape of the input object.

CleanShot 2024-12-19 at 11 20 49@2x

It seems the owner field being included in the input and missing from the schema causes the error.

Work Around

I was able to work around this by simply omitting the owner field from the input object:

async function updateSite(idx: number) {
  const name = window.prompt("Site name") ?? "You entered nothing.";
  const { owner, ...siteWithoutOwner } = sites[idx];
  const record = { ...siteWithoutOwner, name };
  const conf = Amplify.getConfig();
  console.log("Just before", { conf, record });
  const { errors, data } = await client.models.Site.update(record);
  if (data) {
    console.log("The site update was successful: " + data.name);
  } else if (errors) {
    console.log("Errors occured while updating a site", errors);
  }
}

CleanShot 2024-12-19 at 11 27 10@2x

The schema does include owner auth on the Site model. However, the MIS does not have owner under fields, only attributes if the field is implicitly added to the schema via the auth rule.

If the owner field is explicitly added to the schema as a nullable/optional field, then this error doesn't occur.

  Site: a
    .model({
      name: a.string().required(),
      displayName: a.string().required(), // title
      owner: a.string(),
    })

CleanShot 2024-12-19 at 11 22 19@2x

I will mark this as a bug for the team to investigate further. In the meantime, I would recommend using the workaround until we decide how we want to address this behavior and release a fix.

@chrisbonifacio chrisbonifacio added bug Something isn't working and removed question Further information is requested pending-maintainer-response Issue is pending a response from the Amplify team. labels Dec 19, 2024
@MKlaeui
Copy link
Author

MKlaeui commented Dec 20, 2024

Thanks Chris, much appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working data-schema Gen 2
Projects
None yet
Development

No branches or pull requests

3 participants