Error handling
Something always goes wrong: a post is not found, access is denied, the database is down. In Slim every such situation is signalled by throwing an exception, and the error middleware attached in config/middleware.php turns it into a response with the right status code.
HTTP exceptions
Slim has ready-made exception classes for typical errors. One of them is already used in ShowPostAction:
// src/Action/ShowPostAction.php
use Slim\Exception\HttpNotFoundException;
$post = $this->posts->find((int) $args['id']);
if ($post === null) {
throw new HttpNotFoundException($request, 'Post not found');
}Open /posts/999 — the response has code 404. The exception takes the request as the first argument and an optional message as the second.
| Exception | Code | When to throw |
|---|---|---|
HttpBadRequestException | 400 | The request is malformed |
HttpUnauthorizedException | 401 | Login is required |
HttpForbiddenException | 403 | Login is not enough, access is denied |
HttpNotFoundException | 404 | The record or page does not exist |
HttpMethodNotAllowedException | 405 | The method does not fit the route |
They all live in the Slim\Exception namespace. Slim throws 404 for an unknown address and 405 for a wrong method by itself. Any other exception — a bug in the code or an unreachable database — becomes a response with code 500.
The default page
With APP_DEBUG=true the middleware shows details: the exception class, the file, the line and the call chain. With false it shows a short page with the error name. It works, but does not look like the rest of the site.
Your own error template
Create a separate template. It does not extend the layout: the error handler works outside the other layers, and functions such as url_for() may not be connected yet at that moment.
{# templates/error.twig #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error {{ status }}</title>
</head>
<body>
<h1>{{ status == 404 ? 'Page not found' : 'Something went wrong' }}</h1>
<p><a href="/">Back to the home page</a></p>
</body>
</html>Your own handler
addErrorMiddleware() returns the middleware object. It is given a function that builds the response instead of the standard one:
// config/middleware.php
use Psr\Http\Message\ServerRequestInterface;
use Slim\Exception\HttpException;
use Slim\Views\Twig;
$errorMiddleware = $app->addErrorMiddleware($settings['debug'], true, true);
if (!$settings['debug']) {
$errorMiddleware->setDefaultErrorHandler(
function (ServerRequestInterface $request, Throwable $exception) use ($app) {
$status = $exception instanceof HttpException ? $exception->getCode() : 500;
$response = $app->getResponseFactory()->createResponse($status);
return $app->getContainer()->get(Twig::class)
->render($response, 'error.twig', ['status' => $status]);
}
);
}For HTTP exceptions getCode() returns the status code; for everything else 500 is used. The custom handler is enabled only outside debug mode — during development Slim's detailed page is more useful.
Set APP_DEBUG=false in .env and open /posts/999 — your "Page not found" page appears.
Common mistake
Debug mode on a production server shows the visitor file paths, SQL query text and code fragments. The first argument of addErrorMiddleware() must be false on the server, and errors should be learned from the log — the subject of the next lesson. And do not print $exception->getMessage() in your template for 500 errors: it may contain internal details.