# How to setup a 404 action/view in Slim 4?

**URL:** <https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046>\
**Category:** Questions\
**Created:** [April 11, 2020, 7:20pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046 "2020-04-11T19:20:05Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![thierryler](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/thierryler/32/1115_2.png) [@thierryler](https://discourse.slimframework.com/u/thierryler)\
**Post date:** [April 11, 2020, 7:20pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/1 "2020-04-11T19:20:05Z")

</div>

Hello,

When requesting a route that does not exist, I get the Slim 404 error page. How can I setup my own action/view ? I do not find it in the documentation of Slim 4 ☹

Thx, Th.

---

<div class="post-metadata">

**Author:** ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)\
**Post date:** [April 11, 2020, 11:31pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/2 "2020-04-11T23:31:43Z")

</div>

You have at least 3 options (there are more).

In Slim 4 you can register an **error render** per content type, e.g. html/text or application/json:

- [https://akrabat.com/custom-error-rendering-in-slim-4/](https://akrabat.com/custom-error-rendering-in-slim-4/)

You can also register a custom **default error handler** with full access to the response object:

- [http://www.slimframework.com/docs/v4/middleware/error-handling.html](http://www.slimframework.com/docs/v4/middleware/error-handling.html)

The third option is to implement a custom error handler **middleware** (without adding the Slim error middleware to the stack).

---

<div class="post-metadata">

**Author:** ![thierryler](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/thierryler/32/1115_2.png) [@thierryler](https://discourse.slimframework.com/u/thierryler)\
**Post date:** [April 12, 2020, 8:26pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/3 "2020-04-12T20:26:01Z")

</div>

Thanks. So I’d like to write something like this:

```
class HttpErrorHandler extends SlimErrorHandler {

  protected $responder;

  public function __construct(
      Responder $responder,
      CallableResolverInterface $callableResolver,
      ResponseFactoryInterface $responseFactory,
      ?LoggerInterface $logger = null) {
    parent::__construct($callableResolver, $responseFactory, $logger);
    $this->responder = $responder;
  }
  
  protected function respond(): Response {
      $exception = $this->exception;
      $errorCode = $exception->getCode();
      $response = $this->responder->createResponse();
      return $this->responder->render($response, 'myerror.twig', ['errorCode' => $errorCode]);

```

But I can not inject Responder this way. I get an error: Fatal error: Uncaught TypeError: Argument 1 passed to App\Handlers\HttpErrorHandler::\_\_construct() must be an instance of App\Utils\Responder, instance of Slim\CallableResolver given,

I guest there is something I still not understand about injection.

---

<div class="post-metadata">

**Author:** ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)\
**Post date:** [April 12, 2020, 10:10pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/4 "2020-04-12T22:10:44Z")

</div>

According to your example (with Twig) you should implement your own **default error handler** for the Slim error middleware.

Example:

```php
$container = $app->getContainer();
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($container->get(DefaultErrorHandler::class));

```

Here is an example with Twig: [DefaultErrorHandler](https://github.com/odan/slim4-skeleton/blob/master/src/Handler/DefaultErrorHandler.php)

---

<div class="post-metadata">

**Author:** ![thierryler](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/thierryler/32/1115_2.png) [@thierryler](https://discourse.slimframework.com/u/thierryler)\
**Post date:** [April 13, 2020, 8:32am UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/5 "2020-04-13T08:32:29Z")

</div>

Thank for the help. It works now.

For some reasons, in case of 404 error, it does not go throught the middlewares, even if there are not route specified.

I wrote that code:

```
namespace App\Handlers;

use App\Utils\ExceptionDetail;
use App\Utils\Responder;

use DomainException;
use InvalidArgumentException;
use Selective\Validation\Exception\ValidationException;
use Slim\Exception\HttpException;
use Throwable;

use Psr\Log\LoggerInterface as Logger;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;

/**
 * Default Error Renderer.
 * Inspired by https://github.com/odan/slim4-skeleton/blob/master/src/Handler/DefaultErrorHandler.php
 */
class DefaultErrorHandler {

  const TEMPLATE = '/http_error.twig';

  /**
   * @var Responder
   */
  private $responder;
  
  /**
   * @var Logger
   */
  private $logger;

  /**
    * The constructor.
    *
    * @param Responder 
    * @param Logger
    */
  public function __construct(Responder $responder, Logger $logger) {
    $this->responder = $responder;
    $this->logger = $logger;
  }

  /**
    * Invoke.
    *
    * @param Request $request The request
    * @param Throwable $exception The exception
    * @param bool $displayErrorDetails Show error details
    * @param bool $logErrors Log errors
    *
    * @return ResponseInterface The response
    */
  public function __invoke(Request $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors): Response {

    // Log error
    if ($logErrors) {
      $this->logger->error(sprintf(
        'Error: [%s] %s, Method: %s, Path: %s',
        $exception->getCode(),
        ExceptionDetail::getExceptionText($exception),
        $request->getMethod(),
        $request->getUri()->getPath()
      ));
    }

    // Detect status code
    $statusCode = $this->getHttpStatusCode($exception);

    // Error message
    $genericErrorMessage = $this->getErrorMessage($exception, $statusCode, $displayErrorDetails);

    // Render twig template
    $response = $this->responder->createResponse();
    return $this->responder->render(
        $response->withStatus($statusCode), 
        Self::TEMPLATE, 
        ['statusCode' => $statusCode, 'genericErrorMessage' => $genericErrorMessage]);
  }

  /**
    * Get http status code.
    *
    * @param Throwable $exception The exception
    *
    * @return int The http code
    */
  private function getHttpStatusCode(Throwable $exception): int {
    // Detect status code
    $statusCode = 500;

    if ($exception instanceof HttpException) {
      $statusCode = (int)$exception->getCode();
    }

    if ($exception instanceof DomainException || $exception instanceof InvalidArgumentException) {
      // Bad request
      $statusCode = 400;
    }

    if ($exception instanceof ValidationException) {
      // Unprocessable Entity
      $statusCode = 422;
    }

    $file = basename($exception->getFile());
    if ($file === 'CallableResolver.php') {
      $statusCode = 404;
    }

    return $statusCode;
  }

  /**
    * Get error message.
    *
    * @param Throwable $exception The error
    * @param int $statusCode The http status code
    * @param bool $displayErrorDetails Display details
    *
    * @return string The message
    */
  private function getErrorMessage(Throwable $exception, int $statusCode, bool $displayErrorDetails): string {
    // Default error message
    $errorMessage = '500 Internal Server Error';

    if ($statusCode === 403) {
      $errorMessage = '403 Access denied. The user does not have access to this section.';
    } elseif ($statusCode === 404) {
      $errorMessage = '404 Not Found';
    } elseif ($statusCode === 405) {
      $errorMessage = '405 Method Not Allowed';
    } elseif ($statusCode >= 400 && $statusCode <= 499) {
      $errorMessage = sprintf('%s Error', $statusCode);
    }

    if ($displayErrorDetails === true) {
      $errorMessage .= ' - Error details: ' . ExceptionDetail::getExceptionText($exception);
    }

    return $errorMessage;
  }
}

```

Thx, Th.

---

<div class="post-metadata">

**Author:** ![Shihab](https://avatars.discourse-cdn.com/v4/letter/s/edb3f5/32.png) [@Shihab](https://discourse.slimframework.com/u/Shihab)\
**Post date:** [March 22, 2023, 9:11am UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/6 "2023-03-22T09:11:56Z")

</div>

Hi thierryler,

I’m facing the same issue now. Can you pls help me to resolve this?

> [@thierryler](#):
>
> `App\Utils\ExceptionDetail;`

I just copied your code and replaced DefaultErrorHandler.php. Now getting Undefined class ‘ExceptionDetail’. What is this Class?

---

<div class="post-metadata">

**Author:** ![reinier](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/reinier/32/1515_2.png) [@reinier](https://discourse.slimframework.com/u/reinier)\
**Post date:** [March 22, 2023, 10:30am UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/7 "2023-03-22T10:30:34Z")

</div>

its a custom class with a static method that returns the text message from the exception.

probably a class with something like

```auto
public static function getExceptionText(Exception $exception): string
{
    return $exception->getMessage();
}

```

but it probably includes some extra details, because he could have used `$exception->getMessage()` in the logger statement instead of `ExceptionDetail::getExceptionText($exception)`.

TLDR; Just use `$exception->getMessage()` where you are getting the error.

---

<div class="post-metadata">

**Author:** ![Shihab](https://avatars.discourse-cdn.com/v4/letter/s/edb3f5/32.png) [@Shihab](https://discourse.slimframework.com/u/Shihab)\
**Post date:** [March 24, 2023, 11:00am UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/8 "2023-03-24T11:00:58Z")

</div>

when I try to change `return return $this->responder->render(` to `return $this->view->render(` by adding Twig into this Middleware, getting errors like `Uncaught Twig\Error\RuntimeError: Unable to load the "Slim\Views\TwigRuntimeExtension" runtime.`

The reason why I change this is, Twig Template not rendering twig variables and blocks instead of printing it.

How to solve this?

---

<div class="post-metadata">

**Author:** ![thierryler](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/thierryler/32/1115_2.png) [@thierryler](https://discourse.slimframework.com/u/thierryler)\
**Post date:** [March 25, 2023, 5:53pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/9 "2023-03-25T17:53:25Z")

</div>

Here is the code

```auto
<?php
declare(strict_types=1);

namespace App\Utils;

use Throwable;

/**
 * Class ExceptionDetail.
 * copied from https://github.com/odan/slim4-skeleton/blob/master/src/Utility/ExceptionDetail.php
 */
final class ExceptionDetail {
  /**
    * Get exception text.
    *
    * @param Throwable $exception Error
    * @param int $maxLength The max length of the error message
    *
    * @return string The full error message
    */
  public static function getExceptionText(Throwable $exception, int $maxLength = 0): string {
    $code = $exception->getCode();
    $file = $exception->getFile();
    $line = $exception->getLine();
    $message = $exception->getMessage();
    $trace = $exception->getTraceAsString();
    $error = sprintf('[%s] %s in %s on line %s.', $code, $message, $file, $line);
    $error .= sprintf("\nBacktrace:\n%s", $trace);

    if ($maxLength > 0) {
      $error = substr($error, 0, $maxLength);
    }

    return $error;
  }
}

?>

```

---

<div class="post-metadata">

**Author:** ![Shihab](https://avatars.discourse-cdn.com/v4/letter/s/edb3f5/32.png) [@Shihab](https://discourse.slimframework.com/u/Shihab)\
**Post date:** [March 27, 2023, 11:56am UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/10 "2023-03-27T11:56:05Z")

</div>

> [@thierryler](#):
>
> ```auto
> // Render twig template
> $response = $this->responder->createResponse();
> return $this->responder->render(
> $response->withStatus($statusCode), 
> Self::TEMPLATE, 
> ['statusCode' => $statusCode, 'genericErrorMessage' => $genericErrorMessage]);
> }
> 
> ```

Can you help me to render the twig template using Twig View to use extends and blocks?

Error details mentioned [above](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/8)

Another issue while changing a few things getting `Uncaught Twig\Error\LoaderError: Looks like you try to load a template outside configured directories`

But I’m loading template from correct folder `const TEMPLATE = '../resources/views/pages/404.twig';`

---

<div class="post-metadata">

**Author:** ![thierryler](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/thierryler/32/1115_2.png) [@thierryler](https://discourse.slimframework.com/u/thierryler)\
**Post date:** [May 8, 2023, 1:06pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/11 "2023-05-08T13:06:44Z")

</div>

Have you done something like that?

```auto
$settings = $container->get('settings');
  $displayErrorDetails = $settings['displayErrorDetails'];
  $logErrors = $settings['logErrors'];
  $logErrorDetails = $settings['logErrorDetails'];
  $errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, $logErrors, $logErrorDetails);
  $errorMiddleware->setDefaultErrorHandler($container->get(DefaultErrorHandler::class));

```

and

```auto
<?php
declare(strict_types=1);

namespace App\Handlers;

use App\Beans\Usual;
use App\Constantes;
use App\Utils\ExceptionDetail;
use App\Utils\Responder;
use DomainException;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Log\LoggerInterface as Logger;
use Selective\Validation\Exception\ValidationException;
use Slim\Exception\HttpException;
use Throwable;

/**
 * Default Error Renderer.
 * Inspired by https://github.com/odan/slim4-skeleton/blob/master/src/Handler/DefaultErrorHandler.php
 */
class DefaultErrorHandler {

  const TEMPLATE = '/http_error.twig';

  /**
   * @var Responder
   */
  private $responder;
  
  /**
   * @var Logger
   */
  private $logger;

    /**
   * @var Usual
   */
   private $usual;

  /**
    * The constructor.
    *
    * @param Responder 
    * @param Logger
    */
  public function __construct(Responder $responder, Logger $logger, Usual $usual) {
    $this->responder = $responder;
    $this->logger = $logger;
    $this->usual = $usual;
  }

  /**
    * Invoke.
    *
    * @param Request $request The request
    * @param Throwable $exception The exception
    * @param bool $displayErrorDetails Show error details
    * @param bool $logErrors Log errors
    *
    * @return ResponseInterface The response
    */
  public function __invoke(Request $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors): Response {

    $path = $request->getUri()->getPath();

    // Log error
    if ($logErrors) {
      $this->logger->error(sprintf(
        'Error: [%s] %s, Method: %s, Path: %s',
        $exception->getCode(),
        ExceptionDetail::getExceptionText($exception),
        $request->getMethod(),
        $path
      ));
    }

    $loggerUid = $this->getLoggerUid();

    $lang = 'fr';
    // Pour quand on aura d'autres langues
    // if(strpos($path, '/fr') === 0) {
    // $lang = 'fr';
    // } else {
    // // ...
    // }
    $this->usual->lang = $lang;

    // Detect status code
    $httpStatusCode = $this->getHttpStatusCode($exception);
    // $errorCode = $this->getErrorCodeFromStatus($httpStatusCode);
    // $this->usual->addErrorCode($errorCode);

    // Error message
    $genericErrorMessage = $this->getErrorMessage($exception, $httpStatusCode, $displayErrorDetails);
    $genericErrorCode = $httpStatusCode;

    // Render twig template
    $response = $this->responder->createResponse();
    return $this->responder->render(
        $response, 
        Self::TEMPLATE, 
        [
          'httpStatusCode' => $httpStatusCode, 
          'genericErrorMessage' => $genericErrorMessage,
          'genericErrorCode' => $genericErrorCode,
          'loggerUid' => $loggerUid,
        ],
        $httpStatusCode);
  }

  // private function getErrorCodeFromStatus(int $statusCode): string {
  // if(400 <= $statusCode && $statusCode <= 404) {
  // return 'ERROR_' . $statusCode;
  // } else if ($statusCode == 500) {
  // return 'ERROR_500';
  // } else {
  // return 'ERROR_XXX';
  // }
  // }

  /**
    * Get http status code.
    *
    * @param Throwable $exception The exception
    *
    * @return int The http code
    */
  private function getHttpStatusCode(Throwable $exception): int {
    // Detect status code
    $statusCode = 500;

    if ($exception instanceof HttpException) {
      $statusCode = (int)$exception->getCode();
    }

    if ($exception instanceof DomainException || $exception instanceof InvalidArgumentException) {
      // Bad request
      $statusCode = 400;
    }

    if ($exception instanceof ValidationException) {
      // Unprocessable Entity
      $statusCode = 422;
    }

    $file = basename($exception->getFile());
    if ($file === 'CallableResolver.php') {
      $statusCode = 404;
    }

    return $statusCode;
  }

  /**
    * Get error message.
    *
    * @param Throwable $exception The error
    * @param int $statusCode The http status code
    * @param bool $displayErrorDetails Display details
    *
    * @return string The message
    */
  private function getErrorMessage(Throwable $exception, int $statusCode, bool $displayErrorDetails): string {
    // Default error message
    $errorMessage = '500 Internal Server Error';

    if ($statusCode === 403) {
      $errorMessage = '403 Access denied. The user does not have access to this section.';
    } elseif ($statusCode === 404) {
      $errorMessage = '404 Not Found';
    } elseif ($statusCode === 405) {
      $errorMessage = '405 Method Not Allowed';
    } elseif ($statusCode >= 400 && $statusCode <= 499) {
      $errorMessage = sprintf('%s Error', $statusCode);
    }

    if ($displayErrorDetails === true) {
      $errorMessage .= ' - Error details: ' . ExceptionDetail::getExceptionText($exception);
    }

    return $errorMessage;
  }

  protected function getLoggerUid(): string {
    $loggerUid = 'unkonw';
    try {
      $loggerUid = $this->logger->getProcessors()[0]->getUid();
    } catch(Exception $e) {
      // rien
    }
    
    return $loggerUid;
  }

  
}

```

and http\_error.twig is a custom page:

```auto
{% extends 'fr/template.twig' %}

{% block content %}
<div class="container">

  <style>
    .http-error .status-code {
      font-size: 7em;
      color: red;
    }

    .http-error .buttons {
      margin-top: 30px;
    }
  </style>

  <h1>Error...</h1>

  <div class="http-error">
    
    <div class="status-code">{{ httpStatusCode }}</div>

    <div class="message">
      Un erreur s'est produite !

      {% if genericErrorCode == 'CSRF' %}
        Erreur technique HTTP #400-01
      {% else %}
        {{ genericErrorMessage }}
      {% endif %}
    </div>

    <div class="buttons">
      <a href="{{ url_for('home', {'lang': 'fr'}) }}" class="btn btn-primary">Retour à l'accueil</a>
    </div>
  </div>

</div>
{% endblock %}

```

---

<div class="post-metadata">

**Author:** ![Shihab](https://avatars.discourse-cdn.com/v4/letter/s/edb3f5/32.png) [@Shihab](https://discourse.slimframework.com/u/Shihab)\
**Post date:** [May 9, 2023, 3:38pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/12 "2023-05-09T15:38:27Z")

</div>

Thank you so much for your reply.  
What code is inside this `App\Utils\Responder`?  
Mine is `App\Responder\Responder` and this doesn’t have a render function,

 ![Screenshot 2023-05-09 204636](https://canada1.discourse-cdn.com/flex030/uploads/slimframework/original/2X/1/17d2e02209bc883afa746ea696c452ba5fc77582.jpeg)

but this has php render instead. That’s why the Twig template not rendering as the above image.

```auto
<?php

namespace App\Responder;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Interfaces\RouteParserInterface;
use Slim\Views\PhpRenderer;
use function http_build_query;

/**
 * A generic responder.
 */
final class Responder
{
    private PhpRenderer $phpRenderer;

    private RouteParserInterface $routeParser;

    private ResponseFactoryInterface $responseFactory;

    /**
     * The constructor.
     *
     * @param PhpRenderer $phpRenderer The template engine
     * @param RouteParserInterface $routeParser The route parser
     * @param ResponseFactoryInterface $responseFactory The response factory
     */
    public function __construct(
        PhpRenderer $phpRenderer,
        RouteParserInterface $routeParser,
        ResponseFactoryInterface $responseFactory
    ) {
        $this->phpRenderer = $phpRenderer;
        $this->responseFactory = $responseFactory;
        $this->routeParser = $routeParser;
    }

    /**
     * Create a new response.
     *
     * @return ResponseInterface The response
     */
    public function createResponse(): ResponseInterface
    {
        return $this->responseFactory->createResponse()->withHeader('Content-Type', 'text/html; charset=utf-8');
    }

    /**
     * Output rendered template.
     *
     * @param ResponseInterface $response The response
     * @param string $template Template pathname relative to templates directory
     * @param array $data Associative array of template variables
     *
     * @return ResponseInterface The response
     */
    public function withTemplate(ResponseInterface $response, string $template, array $data = []): ResponseInterface
    {
        return $this->phpRenderer->render($response, $template, $data);
    }

    /**
     * Creates a redirect for the given url / route name.
     *
     * This method prepares the response object to return an HTTP Redirect
     * response to the client.
     *
     * @param ResponseInterface $response The response
     * @param string $destination The redirect destination (url or route name)
     * @param array $queryParams Optional query string parameters
     *
     * @return ResponseInterface The response
     */
    public function withRedirect(
        ResponseInterface $response,
        string $destination,
        array $queryParams = []
    ): ResponseInterface {
        if ($queryParams) {
            $destination = sprintf('%s?%s', $destination, http_build_query($queryParams));
        }

        return $response->withStatus(302)->withHeader('Location', $destination);
    }

    /**
     * Creates a redirect for the given url / route name.
     *
     * This method prepares the response object to return an HTTP Redirect
     * response to the client.
     *
     * @param ResponseInterface $response The response
     * @param string $routeName The redirect route name
     * @param array $data Named argument replacement data
     * @param array $queryParams Optional query string parameters
     *
     * @return ResponseInterface The response
     */
    public function withRedirectFor(
        ResponseInterface $response,
        string $routeName,
        array $data = [],
        array $queryParams = []
    ): ResponseInterface {
        return $this->withRedirect($response, $this->routeParser->urlFor($routeName, $data, $queryParams));
    }

    /**
     * Write JSON to the response body.
     *
     * This method prepares the response object to return an HTTP JSON
     * response to the client.
     *
     * @param ResponseInterface $response The response
     * @param mixed $data The data
     * @param int $options Json encoding options
     *
     * @return ResponseInterface The response
     */
    public function withJson(
        ResponseInterface $response,
        $data = null,
        int $options = 0
    ): ResponseInterface {
        $response = $response->withHeader('Content-Type', 'application/json');
        $response->getBody()->write((string)json_encode($data, $options));

        return $response;
    }
}

```

If you can share the Responder dependency details. That may enough to solve this issue.

---

<div class="post-metadata">

**Author:** ![Shihab](https://avatars.discourse-cdn.com/v4/letter/s/edb3f5/32.png) [@Shihab](https://discourse.slimframework.com/u/Shihab)\
**Post date:** [May 30, 2023, 12:33pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/13 "2023-05-30T12:33:25Z")

</div>

> [@thierryler](#):
>
> `use App\Utils\Responder;`

Can you share this dependency details?

---

<div class="post-metadata">

**Author:** ![thierryler](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/thierryler/32/1115_2.png) [@thierryler](https://discourse.slimframework.com/u/thierryler)\
**Post date:** [June 13, 2023, 2:17pm UTC](https://discourse.slimframework.com/t/how-to-setup-a-404-action-view-in-slim-4/4046/14 "2023-06-13T14:17:07Z")

</div>

Actually, I will need to send an entire project to explain. I might send you to an article we wrote (in french).
