Error Handling
Slim ships with a built-in ErrorMiddleware that catches uncaught exceptions and PHP errors, then turns them into an HTTP response instead of a blank page or a raw stack trace dumped straight to the browser. How much detail that response shows — and whether it shows up as HTML or JSON — is entirely up to how you configure it.
Adding the Error Middleware
You enable it with a single call, right after you create the app:
<?php
require __DIR__ . '/../vendor/autoload.php';
$app = \Slim\Factory\AppFactory::create();
$displayErrorDetails = true; // set to false in production
$logErrors = true;
$logErrorDetails = true;
$app->addErrorMiddleware($displayErrorDetails, $logErrors, $logErrorDetails);
$app->run();
The three arguments map directly to the three things you care about: show the reader what went wrong, write it to a log file, and include the full detail (stack trace, file, line) in that log entry.
Development vs Production
| Development | Production | |
|---|---|---|
| $displayErrorDetails | true — see the full error on screen | false — visitors see a generic message |
| $logErrors | true (helpful, not required) | true — you still need the record |
| Who sees the trace | You, in the browser, instantly | Only you, in the log file |
A common pattern is to drive the flag from an environment variable so the same code works in both places:
<?php
$displayErrorDetails = ($_ENV['APP_ENV'] ?? 'production') === 'development';
$app->addErrorMiddleware($displayErrorDetails, true, true);
Custom Error Handlers
addErrorMiddleware() returns the middleware object itself, which lets you register a
custom handler for a specific exception type — for example, a nicer page (or response) for a
404 instead of Slim's default HTML error output:
<?php
use Slim\Exception\HttpNotFoundException;
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$customNotFoundHandler = function ($request, $exception, $displayErrorDetails, $logErrors, $logErrorDetails) use ($app) {
$response = $app->getResponseFactory()->createResponse();
$response->getBody()->write('Sorry, that page could not be found.');
return $response->withStatus(404);
};
$errorMiddleware->setErrorHandler(HttpNotFoundException::class, $customNotFoundHandler);
You can register a different handler for each exception class, or one setDefaultErrorHandler() that catches everything else.
Returning JSON Errors for an API
If your Slim app is a JSON API (see Building JSON APIs), the default HTML error page is the wrong shape entirely — callers expect JSON back, even when something goes wrong. Build the error body yourself and set the content type explicitly:
<?php
use Slim\Exception\HttpNotFoundException;
use Psr\Http\Message\ServerRequestInterface;
$errorMiddleware = $app->addErrorMiddleware(false, true, true);
$jsonNotFoundHandler = function (
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
) use ($app) {
$payload = ['error' => 'Not Found'];
$response = $app->getResponseFactory()->createResponse();
$response->getBody()->write(json_encode($payload));
return $response
->withHeader('Content-Type', 'application/json')
->withStatus(404);
};
$errorMiddleware->setErrorHandler(HttpNotFoundException::class, $jsonNotFoundHandler);
A request to a route that doesn't exist now gets back {"error": "Not Found"} with a 404 status, instead of an HTML page a JSON client can't do anything with.
$displayErrorDetails = true in a production deployment. It leaks full stack traces, file paths, and sometimes database credentials or query text straight to whoever is looking at the response — including attackers. Always flip it to false and rely on your logs instead.