I want to redirect users with RedirectResponse and display a message, but the message is not displayed.

$response = new RedirectResponse($url);

After little debugging I found that my initial (source) URL is loaded twice, and the messages (added with drupal_set_message()) are removed from the session in drupal_get_messages(). So I have no messages on my target $url.

How can I achieve this?

I'm doing it in hook_field_widget_form_alter().

  • 1
    Redirect in a form alter? what are you trying to do? That seems scary. Whenever possible, you should return a redirect response, so that it can be handled by Drupal as necessary. You can't do that in a form alter, but you can set a redirect url or response in a submit callback to $form_state. Consider using that.
    – Berdir
    Commented Apr 22, 2016 at 22:42
  • Problem is that I have form with complex custom elements. This form will work only with GET params. If user will open this form without GET params (for example with manual typing the url), he will be redirected on the dashboard.
    – Eugene
    Commented Apr 23, 2016 at 5:58

8 Answers 8


Set the repeat parameter in drupal_set_message() to TRUE and it will work:

$response = new RedirectResponse($url);
drupal_set_message(t('My message after redirect'), 'status', TRUE);
  • 1
    will work but only the second time you made the redirect. Commented Nov 16, 2017 at 21:24
  • okay then... only spent 6 hours trying to debug this hell, and this answer did it... THANK YOU!
    – Raf A.
    Commented Dec 18, 2017 at 19:52
  • 1
    Block 'Status' under admin>blocks should be enabled to make the message visible.Else you wont see the message. Commented Nov 22, 2018 at 12:30
  • 1
    drupal_set_message is being deprecated, use the Messenger service instead.
    – rreiss
    Commented Nov 25, 2018 at 13:58

I would say that the solution, is not to send the response yourself but in your return.

return $response;
  • it's kind of obvious, but it solved my problem
    – Asy
    Commented Oct 6, 2016 at 7:39

I had this same issue, but using an exit to end the script is not a good idea. Drupal has shutdown functions that it runs at the end of a page load which can be important. Instead I just had to return the redirect response directly:

public function buildForm(array $form, FormStateInterface $form_state) {
  $wizard_data = $form_state->getTemporaryValue('wizard');

  if (empty($wizard_data['csv_data'])) {
    drupal_set_message($this->t('Please upload a file first.'), 'error');
    return $this->redirect('my.route')->send();
  • Where is located this function buildForm?
    – Eugene
    Commented Dec 8, 2016 at 17:37
  • @Eugene buildForm is part of the Form controller class that extends \Drupal\Core\Form\FormBase. For example valuebound.com/resources/blog/… the buildForm function is inside the ResumeForm class. Commented Dec 8, 2016 at 21:41
  • Does it means that your approach will not work for hook_form_alter()? How can I use your approach for node edit form?
    – Eugene
    Commented Dec 9, 2016 at 5:34
  • @Eugene it may work in hook_form_alter(), but you will not have access to the $this->redirect function (that comes from UrlGeneratorTrait). That means you'll need to create a \Drupal\Core\Url object and pass that into a \Symfony\Component\HttpFoundation\RedirectResponse object and return that. It'll have the same affect though. Commented Dec 11, 2016 at 21:56
  • Yes, it will work, but the message will be not displayed as I explained in the initial message of this thread. Unfortunately it's not solution for my case :(
    – Eugene
    Commented Dec 12, 2016 at 4:21

After some investigation I have found that I should interrupt script right after the response. You should be very careful with this approach, because it can break some important actions.

$response = new RedirectResponse($url->toString());
  • 1
    I wouldnt kill the script. I would just look for the URL being called twice, and use another hook like hook_init or something to replace the messages that should be retained after the redirect. Alternatively dont redirect (302) but like use something like drupal_goto which is an internal drupal "go here" without the page refresh.
    – tenken
    Commented Apr 22, 2016 at 19:54

Works for me inside Controller callback. Should not use send(), but just return RedirectResponce object.

drupal_set_message(t('Please log in or create new account.'));
$url = Url::fromRoute('user.login');
$response = new RedirectResponse($url->toString());
return $response;


use Drupal\Core\Url;  
use Symfony\Component\HttpFoundation\RedirectResponse;

$url = Url::fromUri('internal:/');  
$response = new RedirectResponse($url->toString());  

Messages using static service:


Other equivalents:





Don't use send() function, just return $response and it works.

$response = new RedirectResponse(\Drupal::url('user.login'));
// $response->send();
return $response;
  • This answer does not provide any more information than any of the previously given answers... - Consider upvoting the answer of Asy instead. Commented Sep 5, 2018 at 13:37
  • Strangely enough, this worked for me. Adding the $response->send() prevented the message from displaying when the user got to the login page.
    – joekers
    Commented Apr 8, 2020 at 12:03
  • if you are redirecting from a hook in a module file, you should use $response->send(); if you are in a controller then you should use return.
    – wranvaud
    Commented Oct 10, 2022 at 18:12

Recreate the logout functionality. It's just calling user_logout() function.

For this, I create:

A method in SomeController

public function logout() {
  return $this->redirect('<front>', [], ['query' => ['logout' => 1]]);

An event subcriber, subscribe to KernelEvents::REQUEST

$queryLogout = \Drupal::request()->query->get('logout');
if (!empty($queryLogout) && $queryLogout == 1) {
  drupal_set_message("You are logged out");

A router subcriber, altering user.logout route's controller

protected function alterRoutes(RouteCollection $collection) {

  // Change controller who handle logout.
  if ($routeLogout = $collection->get('user.logout')) {
    $routeLogout->setDefault('_controller', '\Drupal\my_module\Controller\SomeController::logout');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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