Error handling lifecycles.js

strapi version : 4.0

im trying to declare custom validation in lifecycles.js. HHOWEVER, ctx is not defined in this file.

Question: how to throw an error in lifecycles.js???


any one… any help :slight_smile: ?

Would also appreciate help with this, it’s the only thing keeping me from fully migrating from v3 to v4 :slight_smile:

Same problem

Derrick of the Strapi Team explained:
“Eh no not really, likewise there is no way to stop the request at the lifecycle level”.
“The lifecycles were not (are not) meant for validation, they are mostly designed to be wrappers
Trigger an email, a notification, fire off a custom webhook, ect.”

I was able to return an error and text, but in the frontend it doesn’t work.

Is this problem still relevant to anyone?

Has anyone managed to do it?

I want to create a slug automatically based on other fields (and I want to validate it first).

I don’t think so. I ended up giving up on using v4 and went back to v3 since it was a validation I was depending on. I also tried asking in the discord but the response was complete silence. I understood that they might be a bit behind when it comes to validations. But you can try discord again and see if things go differently :smiley:

I also asked on Discord, but no answer…

the reason why we need this in life cycle is to write a GLOBAL validation. so regardless where the call came from, (admin, or api) then the validation will be triggered.

  • using global middleware will require careful filtering to avoid running on every request. NOT a practical solution
  • using api middleware. policy or controller, will NOT be triggered if request came from Admin interface. then we need to rewrite the code or use a service … again complicating things.

triggering a validation in lifecycle is a dumdum proof that it will run perfectly

1 year later :slight_smile:

Have you guys found a solution?

I am trying to migrate a big member area from Drupal 10 to Strapi. But it seems that the missing validation layer is a real architectural issue that makes it impossible.

In my case there is a set of validation rules that depend on the workflow state. Fields need to be validated depending on other fields and this again depends on the workflow state (for example the category defines which fields must be set). So the validation logic cannot be static.

The only solution I see is to skip the Strapi UI in general and dont use it as CMS. We would create a second admin frontend in Nextjs that interacts via Rest and can use the same controller/ service pattern. It just creates so much more work. And I am still convinced that validation is not some kind of crazy thing. There must be a solution also in Strapi.

Can this feature be patched? Plugins? Workarounds?

lifecycles.js have error handeling

You can throw an error with throw new ApplicationError('Text strapi admin');
And that error will show up in the strapi admin.

You can also get the full request at the lifecycles layer with strapi.requestContext.get()

1 Like

Thanks @Boegie19

The error response is handy.

The context on the other hand does not contain any field state. Is there another way?
Thank you


  request: {
    method: 'PUT',
    url: '/content-manager/collection-types/',
    header: {
      host: 'localhost:1337',
      connection: 'keep-alive',
      'content-length': '949',
      'sec-ch-ua': '"Chromium";v="110", "Not A(Brand";v="24", "Google Chrome";v="110"',
      'content-type': 'application/json',
      'sec-ch-ua-mobile': '?0',
      authorization: 'Bearer xxx',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ Safari/537.36',
      'sec-ch-ua-platform': '"macOS"',
      accept: '*/*',
      origin: 'http://localhost:8000',
      'sec-fetch-site': 'same-site',
      'sec-fetch-mode': 'cors',
      'sec-fetch-dest': 'empty',
      referer: 'http://localhost:8000/',
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'en-US,en;q=0.9,de-DE;q=0.8,de;q=0.7,es;q=0.6'
  response: {
    status: 404,
    message: 'Not Found',
    header: [Object: null prototype] {
      'content-security-policy': "connect-src 'self' https:;img-src 'self' data: blob:;media-src 'self' data: blob:;default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline'",
      'x-dns-prefetch-control': 'off',
      'expect-ct': 'max-age=0',
      'x-frame-options': 'SAMEORIGIN',
      'strict-transport-security': 'max-age=31536000; includeSubDomains',
      'x-download-options': 'noopen',
      'x-content-type-options': 'nosniff',
      'x-permitted-cross-domain-policies': 'none',
      'referrer-policy': 'no-referrer',
      vary: 'Origin',
      'access-control-allow-origin': 'http://localhost:8000',
      'access-control-allow-credentials': 'true'
  app: { subdomainOffset: 2, proxy: false, env: 'development' },
  originalUrl: '/content-manager/collection-types/',
  req: '<original node req>',
  res: '<original node res>',
  socket: '<original node socket>'

You have access to the body of the request send to the server

Note this could be malformed if someone sends malformed data to the endpoint and this is an exact copy of the data at the start of the process

ctx = strapi.requestContext.get();

Also if you did not already I can recommend joining the discord and joining open office hours what they host every workday at 2:30 CST since then a strapi employ is there to answer all your questions

1 Like

Great that worked… thank you so much…
Yes I am on Discord. But the direct contact sounds great.

Thanks again… !

You know the category I was talking about - that must be used to define which field must be mandatory… it is a reference which I understand cannot be read as long as the content type is not created. If you have another solution I would be almost there :slight_smile:

On create you can just check if the full request that comes in and check and do all the checks on that

for updates
components are always send along (if they are not removed so you can do a db check to check if one got removed) in full and for relations you can get them from the db check if the change the user is trying to aka lets say you have relationship 1 2 3 and 3 always needs to exist you can just check if 3 gets removed and then error

Ok you solved all of my issues :slight_smile: Thank you again.