Custom maintenance page and error handling in Magento 2

This article is about something every store owner would prefer to avoid - how to easily detect that your shop isn’t working and how to quickly react to it. We’re going to have a look at the contents of the `pub/errors/` folder. We will see what we can do with it and what’s the logic behind its functionalities. 

I’d also like to talk about the 503 page (a.k.a. Maintenance mode) and how can you customize it (the right way and the less-right way). I’ll explain why the 404 page can sometimes look differently. We’ll also look into sending automatic emails whenever a customer encounters an error. 

Let’s get to it!

503 Service Unavailable

(HTTP) 503 response code definition:

1 2 The HyperText Transfer Protocol (HTTP) 503 Service Unavailable server error response code indicates that the server is not ready to handle the request. Common causes are a server that is down for maintenance or that is overloaded.

Source: [503 Service Unavailable - HTTP \| MDN]

Magento 2 returns 503 error in two cases: 

  • If the Maintenance Mode is active (`bin/magento maintenance:enable`)
  • If an unhandled exception occurs.

The first scenario is pretty well-known. For example, you’d like to shut down the store during a deployment or perform some operations and you don’t want the customers to access the site. This page will appear by default:

The second case is an unhandled exception on the code. As an example, I added a following line of code to the vendor/magento/magento-catalog/Controller/Category/View.php file.

1 throw new \Exception('Unhandled exception');

So upon entering any page of any category I would see:

This is also something a visitor will see if the store is in production mode. If you view it in developer mode, Magento will display an error with its stack trace. 

These pages have sources in pub/errors/default/503.phtml and in pub/errors/default/report.phtml

In both cases, you can see that it’s just a blank page with black text on it. It’s not at all coherent with the look of the rest of the store. So what can you do to make it coherent? Easy - create a simple maintenance page and replace the old one. As mentioned earlier, there are two ways to go around it.

 Custom maintenance page: method 1 (wrong way)

Theoretically, we can just modify the files, add our styles and texts and the problem is solved. But in reality, it’s not. These files come from the magento/magento2-base package and are copied during Magento installation via Composer. 

So in this case, even if you add these files to the repository, then they will get overwritten and reverted to default. Obviously, it depends on the way you do it but most of the time you will need to use the composer install command to reinstall the packages. 

You can work around this by using the magento-deploy-ignore mechanism. Just add the following line in the composer.json file’s extra section. 

1 2 3 "magento-deploy-ignore": { "*": ["/pub/errors/default/503.phtml"] }

This line informs Composer that it shouldn’t overwrite this file and ignore it. However, this solution will only work until you upgrade Magento. From my experience and web research, I can tell that the entire `pub/errors` folder gets removed during the upgrade you’ll have to restore it from the repository. And this isn’t an optimal solution because new Magento versions can include changes to that folder. 

But that’s an entirely different story connected to the way the `magento-deploy-ignore` works. 

That said, let’s move on to the proper solution!

Custom maintenance page: method 2  (right way)

The second solution - and the right one at that - is creating your own skin. In the pub/errors/ folder, let’s create a new folder called, say, custom. You can either copy the entire pub/erorrs/default folder and modify it or you can just overwrite key files. The error processor falls back to the default skin, so if it doesn’t find a given template in your skin, it will use the default one. 

In order for Magento to know that it should use your skin, create a local.xml file in pub/erorrs/ folder. This file is responsible for the error processor config. For starters, you only need to put there the following lines; we’ll get back to it later: 

1 2 3 4 <?xml version="1.0"?> <config> <skin>custom</skin> </config>

Now, Magento will look for the files in the pub/errors/custom folder. Voilà! You have your own skin. 

In the skin folder, you can change the look of pages like 503, 404, or report (in case of an unhandled error). 

Two different 404 pages.

There are two different types of 404 pages in Magento. The first type is handled by NoRouteHandler. For the frontend, it’s the \Magento\Framework\App\Router\NoRouteHandler class. You can set up these pages in the backend (Stores -> Configuration -> General -> Web -> Default Pages -> CMS No Route Page). By default, it’s CMS Page 404 Not Found

This page will show if you try to go to an address like or to a product/category/cms page that is currently disabled. 

Another 404 page is a simple page like the one you can see below (that we can modify using the skin):

Why the difference? Well, it depends on the server configuration. If you look at a file, like for example nginx.conf.sample, that contains a sample Nginx config for Magento, you will see that this configuration handles particular paths differently. 

Normally, Magento redirects the request to Bootstrap and that’s when 404 pages handled by NoRouteHandler come into play. But paths like pub/, media/ are handled differently. So if you try to go to, then the Magento application will not fully run. In this particular case, the pub/get.php will run, and its logic, in case of a failure, will load the pub/errors/404.php file, which in turn, along with the error processor, will run the 404.phtml file from the skin. 

In addition, in the Ngnix configuration, there’s a error_page 404 403 = /errors/404.php; option. It tells the server which page it should load if it doesn’t find a given URL. And it works similarly for Apache server configuration.

Summing up, it’s important to keep it in mind and handle both 404 pages properly.

Email, when a visitor finds an error

The last thing I’d like to mention are automatic emails whenever a user runs into an error on your website. Specifically, where a report page shows up after getting an unhandled error. Let’s go back to the pub/errors/local.xml file: 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?xml version="1.0"?> <config> <skin>custom</skin> <report> <!-- "action" can be set to "print" to show exception on screen and "email" to send exception on specified email --> <action>email</action> <!-- in "subject" you can set subject of email --> <subject>Store Debug Information</subject> <!-- "email_address" admin email address --> <email_address></email_address> <!-- "trash" is handle about trace info value "leave" is for store on disk value "delete" is for cleaning --> <trash>leave</trash> </report> </config>

With this configuration, a page like this will show up:

And you get an email that an error occurred:

Apart from that, a visitor can fill a form and send a second email to inform you about the problem, but just as well you can hide this form in the skin.


Errors are a part of everyday life but as you can see, they don’t have to be ugly and scary. You can rather make them an integral part of your store. Aside from that, you can be easily notified whenever something bad happens and fix it. Let me know your thoughts and questions in the comments and see you in the next article!