Error & Exception Handling
CakePHP applications come with error and exception handling setup for you. PHPerrors are trapped and displayed or logged. Uncaught exceptions are renderedinto error pages automatically.
Error & Exception Configuration
Error configuration is done in your application’s config/app.php file. Bydefault CakePHP uses Cake\Error\ErrorHandler
to handle both PHP errors andexceptions by default. The error configuration allows you to customize errorhandling for your application. The following options are supported:
errorLevel
- int - The level of errors you are interested in capturing.Use the built-in PHP error constants, and bitmasks to select the level oferror you are interested in. You can set this toE_ALL ^ E_USER_DEPRECATED
to disable deprecation warnings.trace
- bool - Include stack traces for errors in log files. Stacktraces will be included in the log after each error. This is helpful forfinding where/when errors are being raised.exceptionRenderer
- string - The class responsible for rendering uncaughtexceptions. If you choose a custom class you should place the file for thatclass in src/Error. This class needs to implement arender()
method.log
- bool - Whentrue
, exceptions + their stack traces will belogged toCake\Log\Log
.skipLog
- array - An array of exception classnames that should not belogged. This is useful to remove NotFoundExceptions or other common, butuninteresting log messages.extraFatalErrorMemory
- int - Set to the number of megabytes to increasethe memory limit by when a fatal error is encountered. This allows breathingroom to complete logging or error handling.errorLogger
- CakeErrorErrorLogger - The class responsible for loggingerrors and unhandled exceptions.
By default, PHP errors are displayed when debug
is true
, and loggedwhen debug is false
. The fatal error handler will be called independentof debug
level or errorLevel
configuration, but the result will bedifferent based on debug
level. The default behavior for fatal errors isshow a page to internal server error (debug
disabled) or a page with themessage, file and line (debug
enabled).
Note
If you use a custom error handler, the supported options willdepend on your handler.
Changing Exception Handling
Exception handling offers several ways to tailor how exceptions are handled. Eachapproach gives you different amounts of control over the exception handlingprocess.
- Customize the error templates This allows you to change the rendered viewtemplates as you would any other template in your application.
- Customize the ErrorController This allows you to control how exceptionpages are rendered.
- Customize the ExceptionRenderer This allows you to control how exceptionpages and logging are performed.
- Create & register your own error handler This gives you completecontrol over how errors & exceptions are handled, logged and rendered.
Customize Error Templates
The default error handler renders all uncaught exceptions your applicationraises with the help of Cake\Error\ExceptionRenderer
, and your application’sErrorController
.
The error page views are located at templates/Error/. All 4xx errors usethe error400.php template, and 5xx errors use the error500.php. Yourerror templates will have the following variables available:
message
The exception message.code
The exception code.url
The request URL.error
The exception object.
In debug mode if your error extends Cake\Core\Exception\Exception
thedata returned by getAttributes()
will be exposed as view variables as well.
Note
You will need to set debug
to false, to see your error404 anderror500 templates. In debug mode, you’ll see CakePHP’s developmenterror page.
Customize the Error Page Layout
By default error templates use templates/Layout/error.php for a layout.You can use the layout
property to pick a different layout:
- // inside templates/Error/error400.php
- $this->layout = 'my_error';
The above would use templates/Layout/my_error.php as the layout for yourerror pages.
Many exceptions raised by CakePHP will render specific view templates in debugmode. With debug turned off all exceptions raised by CakePHP will use eithererror400.php or error500.php based on their status code.
Customize the ErrorController
The App\Controller\ErrorController
class is used by CakePHP’s exceptionrendering to render the error page view and receives all the standard requestlife-cycle events. By modifying this class you can control which components areused and which templates are rendered.
If your application uses routing-prefixes you can create custom errorcontrollers for each routing prefix. For example, if you had an Admin
prefix. You could create the following class:
- namespace App\Controller\Admin;
- use App\Controller\AppController;
- use Cake\Event\EventInterface;
- class ErrorController extends AppController
- {
- /**
- * Initialization hook method.
- *
- * @return void
- */
- public function initialize(): void
- {
- $this->loadComponent('RequestHandler');
- }
- /**
- * beforeRender callback.
- *
- * @param \Cake\Event\EventInterface $event Event.
- * @return void
- */
- public function beforeRender(EventInterface $event)
- {
- $this->viewBuilder()->setTemplatePath('Error');
- }
- }
This controller would only be used when an error is encountered in a prefixedcontroller, and allows you to define prefix specific logic/templates as needed.
Change the ExceptionRenderer
If you want to control the entire exception rendering and logging process youcan use the Error.exceptionRenderer
option in config/app.php to choosea class that will render exception pages. Changing the ExceptionRenderer isuseful when you want to provide custom error pages for application specificexception classes.
Your custom exception renderer class should be placed in src/Error. Let’sassume our application uses App\Exception\MissingWidgetException
to indicatea missing widget. We could create an exception renderer that renders specificerror pages when this error is handled:
- // In src/Error/AppExceptionRenderer.php
- namespace App\Error;
- use Cake\Error\ExceptionRenderer;
- class AppExceptionRenderer extends ExceptionRenderer
- {
- public function missingWidget($error)
- {
- $response = $this->controller->response;
- return $response->withStringBody('Oops that widget is missing.');
- }
- }
- // In config/app.php
- 'Error' => [
- 'exceptionRenderer' => 'App\Error\AppExceptionRenderer',
- // ...
- ],
- // ...
The above would handle our MissingWidgetException
,and allow us to provide custom display/handling logic for those applicationexceptions.
Exception rendering methods receive the handled exception as an argument, andshould return a Response
object. You can also implement methods to addadditional logic when handling CakePHP errors:
- // In src/Error/AppExceptionRenderer.php
- namespace App\Error;
- use Cake\Error\ExceptionRenderer;
- class AppExceptionRenderer extends ExceptionRenderer
- {
- public function notFound($error)
- {
- // Do something with NotFoundException objects.
- }
- }
Changing the ErrorController Class
The exception renderer dictates which controller is used for exceptionrendering. If you want to change which controller is used to render exceptions,override the _getController()
method in your exception renderer:
- // in src/Error/AppExceptionRenderer
- namespace App\Error;
- use App\Controller\SuperCustomErrorController;
- use Cake\Error\ExceptionRenderer;
- class AppExceptionRenderer extends ExceptionRenderer
- {
- protected function _getController()
- {
- return new SuperCustomErrorController();
- }
- }
- // in config/app.php
- 'Error' => [
- 'exceptionRenderer' => 'App\Error\AppExceptionRenderer',
- // ...
- ],
- // ...
Creating your Own Error Handler
By replacing the error handler you can customize the entire error & exceptionhandling process. By extending Cake\Error\BaseErrorHandler
you can customizedisplay logic more simply. As an example, we could build a class calledAppError
to handle our errors:
- // In config/bootstrap.php
- use App\Error\AppError;
- $errorHandler = new AppError();
- $errorHandler->register();
- // In src/Error/AppError.php
- namespace App\Error;
- use Cake\Error\BaseErrorHandler;
- class AppError extends BaseErrorHandler
- {
- public function _displayError($error, $debug)
- {
- echo 'There has been an error!';
- }
- public function _displayException($exception)
- {
- echo 'There has been an exception!';
- }
- }
The BaseErrorHandler
defines two abstract methods. _displayError()
isused when errors are triggered. The _displayException()
method is calledwhen there is an uncaught exception.
Changing Fatal Error Behavior
Error handlers convert fatal errors into exceptions and re-use theexception handling logic to render an error page. If you do not want to show thestandard error page, you can override it:
- // In src/Error/AppError.php
- namespace App\Error;
- use Cake\Error\BaseErrorHandler;
- class AppError extends BaseErrorHandler
- {
- // Other methods.
- public function handleFatalError($code, $description, $file, $line)
- {
- echo 'A fatal error has happened';
- }
- }
Creating your own Application Exceptions
You can create your own application exceptions using any of the built in SPLexceptions, Exception
itself, or Cake\Core\Exception\Exception
.If your application contained the following exception:
- use Cake\Core\Exception\Exception;
- class MissingWidgetException extends Exception
- {
- }
You could provide nice development errors, by creatingtemplates/Error/missing_widget.php. When in production mode, the aboveerror would be treated as a 500 error and use the error500 template.
If your exceptions have a code between 400
and 506
the exception codewill be used as the HTTP response code.
The constructor for Cake\Core\Exception\Exception
allows you topass in additional data. This additional data is interpolated into the the_messageTemplate
. This allows you to create data rich exceptions, thatprovide more context around your errors:
- use Cake\Core\Exception\Exception;
- class MissingWidgetException extends Exception
- {
- // Context data is interpolated into this format string.
- protected $_messageTemplate = 'Seems that %s is missing.';
- // You can set a default exception code as well.
- protected $_defaultCode = 404;
- }
- throw new MissingWidgetException(['widget' => 'Pointy']);
When rendered, this your view template would have a $widget
variable set. Ifyou cast the exception as a string or use its getMessage()
method you willget Seems that Pointy is missing.
.
Logging Exceptions
Using the built-in exception handling, you can log all the exceptions that aredealt with by ErrorHandler by setting the log
option to true
in yourconfig/app.php. Enabling this will log every exception toCake\Log\Log
and the configured loggers.
Note
If you are using a custom exception handler this setting will haveno effect. Unless you reference it inside your implementation.
Built in Exceptions for CakePHP
HTTP Exceptions
There are several built-in exceptions inside CakePHP, outside of theinternal framework exceptions, there are severalexceptions for HTTP methods
- exception
Cake\Http\Exception\
InvalidCsrfTokenException
- Used for doing a 403 error caused by an invalid CSRF token.
- exception
Cake\Http\Exception\
MethodNotAllowedException
- Used for doing a 405 Method Not Allowed error.
For more details on HTTP 4xx error status codes see RFC 2616#section-10.4.
- exception
Cake\Http\Exception\
ServiceUnavailableException
- Used for doing a 503 Service Unavailable error.
For more details on HTTP 5xx error status codes see RFC 2616#section-10.5.
You can throw these exceptions from your controllers to indicate failure states,or HTTP errors. An example use of the HTTP exceptions could be rendering 404pages for items that have not been found:
- use Cake\Http\Exception\NotFoundException;
- public function view($id = null)
- {
- $article = $this->Articles->findById($id)->first();
- if (empty($article)) {
- throw new NotFoundException(__('Article not found'));
- }
- $this->set('article', $article);
- $this->viewBuilder()->setOption('serialize', ['article']);
- }
By using exceptions for HTTP errors, you can keep your code both clean, and giveRESTful responses to client applications and users.
Using HTTP Exceptions in your Controllers
You can throw any of the HTTP related exceptions from your controller actionsto indicate failure states. For example:
- use Cake\Network\Exception\NotFoundException;
- public function view($id = null)
- {
- $article = $this->Articles->findById($id)->first();
- if (empty($article)) {
- throw new NotFoundException(__('Article not found'));
- }
- $this->set('article', 'article');
- $this->viewBuilder()->setOption('serialize', ['article']);
- }
The above would cause the configured exception handler to catch andprocess the NotFoundException
. By default this will create an errorpage, and log the exception.
Other Built In Exceptions
In addition, CakePHP uses the following exceptions:
- exception
Cake\Controller\Exception\
MissingComponentException
- A configured component could not be found.
- exception
Cake\Controller\Exception\
MissingActionException
- The requested controller action could not be found.
- exception
Cake\Controller\Exception\
PrivateActionException
- Accessing private/protected/_ prefixed actions.
- exception
Cake\Console\Exception\
MissingShellMethodException
- The chosen shell class has no method of that name.
- exception
Cake\Database\Exception\
MissingExtensionException
- A PHP extension is missing for the database driver.
- exception
Cake\ORM\Exception\
PersistenceFailedException
- An entity couldn’t be saved/deleted while using
Cake\ORM\Table::saveOrFail()
orCake\ORM\Table::deleteOrFail()
.
- exception
Cake\Datasource\Exception\
RecordNotFoundException
- The requested record could not be found. This will also set HTTP responseheaders to 404.
- exception
Cake\Routing\Exception\
MissingControllerException
- The requested controller could not be found.
- exception
Cake\Routing\Exception\
MissingRouteException
- The requested URL cannot be reverse routed or cannot be parsed.
- exception
Cake\Routing\Exception\
MissingDispatcherFilterException
- The dispatcher filter could not be found.
- exception
Cake\Core\Exception\
Exception
- Base exception class in CakePHP. All framework layer exceptions thrown byCakePHP will extend this class.
These exception classes all extend Exception
.By extending Exception, you can create your own ‘framework’ errors.
Cake\Core\Exception\Exception::
responseHeader
($header = null, $value = null)- See
Cake\Network\Request::header()
All Http and Cake exceptions extend the Exception class, which has a methodto add headers to the response. For instance when throwing a 405MethodNotAllowedException the rfc2616 says:
- "The response MUST include an Allow header containing a list of valid
- methods for the requested resource."