payloadcms / payload

Payload is the open-source, fullstack Next.js framework, giving you instant backend superpowers. Get a full TypeScript backend and admin panel instantly. Use Payload as a headless CMS or for building powerful applications.
https://payloadcms.com
MIT License
23.1k stars 1.44k forks source link

"Cannot read properties of null (reading 'id')" in afterChange Hook #7134

Closed praveenvijayan closed 1 month ago

praveenvijayan commented 1 month ago

Link to reproduction

No response

Payload Version

3.0.0-beta.61

Node Version

v20.15.0

Next.js Version

14.2.4

Describe the Bug

I am encountering an error when using the afterChange hook in my Payload CMS project. The error message is "Cannot read properties of null (reading 'id')" and occurs during the payload.update call.

Error: 
{
  docs: [],
  errors: [
    {
      id: '6690f175a928b6b33c497328',
      message: "Cannot read properties of null (reading 'id')"
    }
  ]
}

Hook Implementation (hooks/businessHooks.ts)

export const assignBusinessUnit = async ({ context, doc, req }: any) => {
  const { payload, user } = req;

  const businessOwner = await payload.find({
    collection: "businesses",
    where: {
      "owner.id": {
        equals: user.id,
      },
    },
  });

  if (businessOwner?.docs?.length == 1) {
    await payload.update({
      collection: "businesses",
      id: doc.id,
      data: {
        ...doc,
        isDefaultBusinessUnit: true,
      },
    });
  }
};

Business Collection Configuration (collections/Business.ts):

export const Businesses: CollectionConfig = {
  slug: "businesses",
  admin: {
    useAsTitle: "name",
  },
  access: {

  },
  hooks: {
    beforeChange: [assignOwner],
    afterChange: [assignBusinessUnit],
  },
  fields: [
    {
      name: "name",
      type: "text",
      required: true,
      unique: true,
    },
    {
      name: "isDefaultBusinessUnit",
      type: "checkbox",
      defaultValue: false,
      admin: {
        disabled: true,
      },
    },
  ],
};

Observations:

The error occurs specifically at the line where payload.update is called with doc.id. The doc object appears to be null or undefined at this point, even though it should be valid.

Expected Behavior:

The afterChange hook should successfully update the isDefaultBusinessUnit field for the specified document in the businesses collection without encountering a null doc.id.

Actual Behavior:

The hook throws a TypeError indicating that it cannot read the id property of null.

Reproduction Steps

Define an afterChange hook that updates a document in the businesses collection. Attempt to update the document with the following hook implementation:

Adapters and Plugins

No response

chrisvanmook commented 1 month ago

I got the same issue, but it happens only when I use the postgres adapter. MongoDB seems to go fine. To reproduce: https://github.com/chrisvanmook/payload/commit/b74f0c747d196dcf0d34231414e9af21d52b138c

jmikrut commented 1 month ago

@kendelljoseph let's get @chrisvanmook's code up and running to see if we can spot the issue.

JarrodMFlesch commented 1 month ago

@praveenvijayan you just need to thread req through into your payload. operations.

i.e.

const assignOwner: CollectionBeforeChangeHook = async ({ req, data, operation }) => {
  if (operation === 'create') {
    data.owner = req.user.id
  }

  return data
}

const assignBusinessUnit: CollectionAfterChangeHook = async ({ context, doc, req, data }: any) => {
  const { payload, user } = req

  const businessOwner = await payload.find({
    collection: 'businesses',
    where: {
      'owner.id': {
        equals: user.id,
      },
    },
    req,
  })

  if (businessOwner?.docs?.length == 1) {
    await payload.update({
      collection: 'businesses',
      id: doc.id,
      data: {
        ...doc,
        isDefaultBusinessUnit: true,
      },
      req,
    })
  }

  return data
}
github-actions[bot] commented 3 hours ago

This issue has been automatically locked. Please open a new issue if this issue persists with any additional detail.