If you want to extend the core exception handling, you can override the handler with a custom handler.
See also How to extend the error and exception handling.

In this example we will describe how to check user access in a controller action and throw a 403 if the user is not logged in. This is just one example of many use cases.

Let's start with the controller action. In your action, you want to check if a user is logged in, if not, throw an error.



if ($this->feUser === null) {
  throw new LoginDeniedException('Access denied');


We defined an own Execption class for this.



namespace Vendor\CstmExtension\Exception;

class LoginDeniedException extends \Exception


There is an exception handler at content element level. This Typoscript config allows you to override this handler.



config.contentObjectExceptionHandler = Vendor\CstmExtension\Error\Frontend\ProductionExceptionHandler


In your handler, you can catch the LoginDeniedException and do whatever you want, such as redirecting to the login page as shown here.



class ProductionExceptionHandler extends \TYPO3\CMS\Frontend\ContentObject\Exception\ProductionExceptionHandler
    use ExceptionHandlerTrait;

    public function handle(
        \Exception $exception, 
        AbstractContentObject $contentObject = null, 
        $contentObjectConfiguration = []): string
        if ($exception instanceof LoginDeniedException) {
            $request = $GLOBALS['TYPO3_REQUEST'];
            header('Location: ' . $this->getLoginPage((string)$request->getUri()), true, 302);
        return parent::handle($exception, $contentObject, $contentObjectConfiguration);


It's a good habit to define the login page in the errorHandling section of your site config.



    errorCode: 403
    errorHandler: Page
    errorContentSource: 't3://page?uid=3427'


The getLoginPage function finally reads the config and builds a valid link to the target page.



trait ExceptionHandlerTrait
    protected function getLoginPage(string $url): string
        // default is to root page
        $link = '/';

        // loads the site config as array
        $request = $GLOBALS['TYPO3_REQUEST'];
        $site = $request->getAttribute('site')->getConfiguration();

        // check and loop if there is a 403 handler
        if (!empty($config['errorHandling'])) {
            foreach ($config['errorHandling'] as $errorHandler) {
                if (!empty($errorHandler['errorCode']) && !empty($errorHandler['errorContentSource']) 
                                && $errorHandler['errorCode'] == 403) {
                    // add the calling url as return attribute
                    $signed = $this->signUrl($url);
                    // use the typolink renderer to get a valid url
                    $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
                    $link = $contentObject->typoLink_URL([
                        'parameter' => $errorHandler['errorContentSource'],
                        'additionalParams' => '&return_url=' . $signed,
        return $link;

    protected function signUrl(string $url): string
        return sprintf(
            GeneralUtility::hmac($url, FrontendUserAuthentication::class)