Content-type lifecycle hooks not firing

Hi All,

I am 100% new to Strapi. This is day 2.5 of development.

I have a content-type defined called note. So in the code I see src/api/note/content-types/note/schema.json
It is my understanding that if I want to hook into the lifecycle events I need to create a file in that folder which is at the same level as schema.json this file should be called lifecycles.ts
I have done this, and this is what the entirety of my file looks like presently

  beforeCreate(event) {
    console.log("You can't create a note");

    throw new Error("You can't create a note");
  beforeUpdate(event) {
    console.log("You can't create a note");

    throw new Error("You can't create a note");
When I create or update a note through the front-end, the note creates or updates with no errors and no sign of a log (not that I am sure you can console.log like this, but it was a worth a try).
I am not sure what else to do to get these lifecycle events to fire. 

My present goal is actually to create a custom error message. On one of my fields I have a regex which works fine, but the error message is rubbish and I want to customise it. I do not see a way in the docs to do this so I presume hooking into the events is one way. Even if there is a better way, can you ALSO tell my why my events do not seem to be hooked.

Thanks in advance!

<i>This topic has been created from a Discord post (1227578004058673212) to give it more visibility.
It will be on Read-Only mode here.
<a href="">Join the conversation on Discord</a></i>

anyone at all?

Hey, what do you mean “update a note through the front-end”? Do you mean strapi admin panel? Is the project TS or JS?

Hi <@171311917405700096>, yes through the admin panel. It is TS.

this is what my lifecycles.ts look look like:

import axios from "axios";

let previousVerificationStatus: string | null = null;

export default {
  async beforeUpdate(event: { params: { where: { id: number } } }) {
    const { where } = event.params;
    const entity = await strapi.entityService.findOne(
        fields: ["verification_status"],
    previousVerificationStatus = entity.verification_status;
  async afterUpdate(event: {
    params: {
      data: { verification_status: string; firstName: string; email: string };
  }) {
    const { data } = event.params;
    if (
      data.verification_status === "verified" &&
      previousVerificationStatus !== "verified"
    ) {
      console.log("User has been verified");

      const emailData = {
        subject: "Your account has been verified",
        html_content: `<p>Welcome, ${data.firstName}! Your account has been <strong>verified</strong>! You can now start adding listings. 🙂</p>`,
        to: [],
      try {
        const response = await
            headers: {
              "Content-Type": "application/json",
          "Verification email sent successfully. Server said:",

      } catch (error) {
          "Failed to send verification email:",
          JSON.stringify(, null, 2)
    previousVerificationStatus = null;

It’s placed in api/kinde-user/content-types/kinde-user

alongside lifecycle.ts

maybe try export default instead of module.exports?

I thank you both for your responses, the hooks started firing, I think it was probably export default. I switched to a different branch and was pairing with a colleague, showing them how the hooks refused to fire. As I finished the demo code on that branch the hooks were firing, which was quite funny as I was trying to demonstrate to him how they would not work.