When saving / updating node, i need to validate if certain fields combination is unique. Unique field module is supposed to allow this, but that feature is not working (validating only single field). So i created my own hook:

function mymodule_node_presave(\Drupal\Core\Entity\EntityInterface $node) {

  if ($node->bundle() == 'mycontent') {

    $term = \Drupal\taxonomy\Entity\Term::load($node->get('field_mytaxonomy')->target_id);

    $query = \Drupal::entityQuery('node');
    $query->condition('type', 'mycontent');
    $query->condition('field_mydate', $node->get('field_mydate')->value, '=');
    $query->condition('field_mytaxonomy', $term->id(), '=');

    $nids = $query->execute();

    if ($nids) {
      drupal_set_message('Fields are not unique!', 'error');
      // I need to prevent saving of node here      

Detection of node with duplicite values being created works. How do i prevent saving that node?


How do i prevent saving that node?

If you want to prevent that the node is saved in a presave method or hook you have to throw an exception:

throw new \Exception(t('Fields are not unique!'));

More user friendly would be to check this in the form first and give the user a chance to correct the input before you throw an exception.

Double checking this in presave is still a good idea to make sure, that no incorrect node content gets saved, no matter which form, Rest API or code is used. If someone gets past the first level of checks in the form you have no other option than to throw an exception.


In case an exception is raised, you can replace the default 500 response with a custom error handling in an exception subscriber, see Handle database connection exception via custom handler

  • Ok, it stops node from being saved, save exception to DB log, but it "breaks" page with an error (The website encountered an unexpected error. Please try again later.) for front end user. Any way to modify this to return to content add page? – tdd Dec 18 '16 at 15:29
  • If it is your code that saves the entity you can enclose the ->save() method in a try/catch. - But I'm not sure if you read to complete answer. If it is a form, that is saving the data, then use form validation to prevent that the form is trying to save incorrect data. – 4k4 Dec 18 '16 at 16:11
  • An example would be a division by zero. You would tell the user in form validation, that he should not enter a zero. But if this first level of check fails, then you get an exception later. That's the same here, the check in presave should be the second level of checks and should only be raised, if something unexpected goes wrong. – 4k4 Dec 18 '16 at 16:19

That is not the right hook to do validations. Use hook_form_FORM_ID_alter() to add a validation function.

$form['#validate'][] = 'my_custom_validate';

Then in your custom validation function:

$term = $form_state->getValue('field_mytaxonomy');
// Your logic here.
$form_state->setErrorByName('field_mytaxonomy', t('Fields are not unique!'));

I had a similar requirement, and wanted a nicer solution than simply throwing an exception. The following seemed to work well for me, in my hook_node_presave():

$response = new RedirectResponse(\Drupal::request()->getRequestUri());
drupal_set_message(t('This is my error message'), 'error', TRUE);
  • 1
    You'll need the following "use" statement at the top of the file where this code is used: use Symfony\Component\HttpFoundation\RedirectResponse; (drupal.org/node/2023537) – ben.hamelin Oct 19 '17 at 17:46
  • 1
    Custom code should not send a response. The job of the Drupal kernel is to return a response. One way to do this is by setting the response in an event subscriber, see drupal.stackexchange.com/a/235942/47547 – 4k4 Oct 1 '18 at 9:16
  • 1
    Note that this does not work for custom entities. – Stef Van Looveren Nov 19 '19 at 13:52

I've used the user34185 solution in the safedelete module, for a working example download the safedelete module for Drupal 8/9 https://drupal.org/project/safedelete

  • 1
    Instead of just saying that the module solves the problem. You might want to describe how the module can prevent the saving of the node as the question asks. – Shawn Conn Jun 9 '20 at 21:51
  • use case slightly different but rather than using hook_node_presave I used hook_node_predelete(EntityInterface $entity) { see code: git.drupalcode.org/project/safedelete/-/blob/1.0.x/… – Joseph Olstad Sep 9 '20 at 20:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.