Manually trigger HTTP ERROR with response body

I have set up renderer in the default error handler to display custom error pages which works fine; when I for instance type in a non-existent url path it will render my custom error page with the correct 404 status code.

But how can I display custom error page when manually triggering an http error, say error 401 with $response->withStatus(401)? Anything I write to the response body (or header) or template I try to render when triggering an http error is ignored and the default Apache error for that status code is displayed instead.

The simplest solution is to use one of Slim’s HttpException classes:

use Slim\Exception\HttpUnauthorizedException;
// ...

throw new HttpUnauthorizedException($request);

Hi, yes I have tried that, too. Same issue. The status code is correct but it only displays the Apache default error. I’ve tried with HttpNotFoundException.

Sorry to nag, but can you please explain to me why this happens? I am using the default error handler to test now. The json 404 error is shown if I type a bogus url, but when I throw the error manually, or use $response->withStatus(404), the default Apache error is shown, no matter what template I render or text I write to the body.

Have you added the Slim ErrorMiddleware?

I have the following as default per the Slim 4 Skeleton:

return function (App $app) {
    $app->addBodyParsingMiddleware();
    $app->add(ValidationExceptionMiddleware::class);
    $app->addRoutingMiddleware();
    $app->add(BasePathMiddleware::class);
    $app->add(ErrorMiddleware::class);
};

Can you show the code how you throw the exception?

Make sure you pass the request object to the constructor. Example:

use Slim\Exception\HttpNotFoundException;
// ...
throw new HttpNotFoundException($request);

Otherwise you will get just a Internal Server Error 500 Too few arguments to function lim\\Exception\\HttpSpecializedException::__construct()

I use the exact same code as you have there, from inside an Action that does nothing else. I am not getting a 500 server error, I get the correct status, ie 404 (or whatever error I throw), but I cannot use custom body for the error.

EDIT: The request object is passed to __invoke().

In this case, make sure you add a default error handler to the Slim ErrorMiddleware within the DI container definiton for ErrorMiddleware::class

$errorMiddleware->setDefaultErrorHandler($customErrorHandler);

It is set to the default App\Handler\DefaultErrorHandler. Even that without ANY modification has the same problem. The error details are not shown when manually triggering the error.

Can you post a screenshot?

BTW: The error details are disabled by default (for security reasons).
You can change it in the settings:

$settings['error']['display_error_details'] = true;

Yes, it is set and like I said, it works (shows the details) if I try to open a non-existant path in the url. It only does not work when I trigger the error manually. I don’t know how else I can explain it.

If I use address http://myserver/some/path/that/does/notexist, or when there is a 500 server error, then everything works fine (the json error details are shown).

But when I trigger the error manually in the code, by using throw new HttpNotFoundError($request);, the correct status is shown but not the error details. The default Apache error is shown.

In other words, when I trigger the error manually using throw new HttpNotFoundError($request); I get this:

…instead of the error details.

OK, this is very strange. Normally this is not the default behavior. I guess that Apache could be configured in a special way.

I’ve been searching through Apache documentation, but no luck.

But why does it work when the framework throws the error and not when I do it manually from an action?

Technically it’s the same, because the Slim RoutingMiddleware also throws the Slim\Exception\HttpNotFoundException in line 91. See here.

Try to check your mod_rewrite rules in your .htaccess files.
You could also try this Slim setup checker and post the result.

mod_rewrite is reported as not found by the checker, but it is enabled and works. The methods used in that checker will not detect mod_rewrite when running php-fpm.

I am stumped. It cannot be a mod_rewrite problem anyway, since it works when the error is thrown from the routing middleware. Am I right? It would seem to me that throwing it from the Action, the body and headers are replaced somewhere.

But anyway, rewriting works and this is my .htaccess file:

# Redirect to front controller
RewriteEngine On
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]

OK, got it working. I realised it was only an issue when using the ‘/’ root path. So I changed the .htaccess to:

RewriteEngine On
RewriteBase /
RewriteRule ^ index.php [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /index.php [L]

Thanks for all your help.

1 Like