Dynamically change the "access denied page" title and body This is not a question about changing or preprocessing the twig template of the 403 page.
I have a controller with an access function called by the _custom_access key of my route.
In some circumstance, this function is returning AccessResult::forbidden(&quot;a good reason&quot;); which lead to my default 403 page.
Most of the case, this is the behavior I would like to have, but in few cases, I would like to have another title and another message for this page like &quot;You can not access because you eat too much chocolate&quot;
Should I create a new custom error route and send a new response to this route from my access function? (hint: I tried without success)
Any idea?
Edit to add: Thanks to 4k4, I have added a custom ExceptionHtmlSubscriber extending DefaultExceptionHtmlSubscriber in order to override the on403() method.
Here is my code:
class TXSExceptionHtmlSubscriber extends DefaultExceptionHtmlSubscriber {
  /**
   * {@inheritdoc}
   */
  public function on403(ExceptionEvent $event) {
    $my_condition=extract_from_event($event);
    if($my_condition){
      // I am not sure it is what should be done here
      $this-&gt;makeSubrequest($event, '/my_custom_error_path/my_custom_error_code', Response::HTTP_FORBIDDEN);
    }else {
      parent::$this-&gt;on403($event);
    }
  }
  /**
   * {@inheritdoc}
   */
  protected static function getPriority() {
    return 1000;
  }
}

So far, I have 2 questions:
1-Unfortunately my custom on403() method is never called (on the other hand, the on403() method DefaultExceptionHtmlSubscriber is called): What I am missing?
2-Let say that my custom on403() method is called: what should be the code to redirect the user on my custom 403 page containing my custom message (ie: it could be nice to display the reason of the AccessResult AccessResult::forbidden(&quot;a good reason&quot;);
Access functions are only for calculating access results. You can't do anything else because this function is called multiple times, not only for incoming routes but also for outbound links.
To set a response use on403() of an ExceptionHtmlSubscriber. You can also set the result of a sub-request if you want a themed 403 message. See How can we catch the acces denied exception?
Edit: Answering further questions

1-Unfortunately my custom on403() method is never called (on the other
hand, the on403() method DefaultExceptionHtmlSubscriber is called):
What I am missing?

You need to register the service in mymodule.services.yml:
services:
  mymodule.exception_subscriber:
    class: Drupal\mymodule\EventSubscriber\MymoduleExceptionHtmlSubscriber
    tags:
      - { name: event_subscriber }


2-Let say that my custom on403() method is called: what should be the
code to redirect the user on my custom 403 page containing my custom
message (ie: it could be nice to display the reason of the
AccessResult AccessResult::forbidden(&quot;a good reason&quot;);

You find the message in the exception object:
public function on403(ExceptionEvent $event) {
  // ...
  if ($my_condition) {
    $message = $event-&gt;getThrowable()-&gt;getMessage();
    $event-&gt;setResponse(new Response($message, 403));
  }
}

BTW you don't need to call parent::on403($event) because the parent registered with a lower priority will be called automatically when your event subscriber doesn't set a response.