hapi — How to Handle 404 Responses for Missing Routes

Developing your web app isn’t only about the happy path. You need to take care of proper error handling and that applies to more than just showing creative error messages for bad user inputs on forms.

Start the error handling journey with missing resources which is a common scenario: just append a random route path to your url.

This tutorial shows you how to set up a 404 route handler that can render a view template or reply JSON for REST requests.

hapi Series Overview

Prepare Your Project

By default, hapi will properly respond with a 404 error message and status code for unavailable resources. If you’re building an app that renders web views, you want to keep the user in context and render a proper template as a 404 response as well. For REST requests, you’re better off by replying JSON.

If not already done, go ahead and install the following dependencies:

npm i -S vision boom  

You’ll use vision to render and reply the 404 web view. With boom, you’ve an error utility which automatically sets the correct 404 response status code and creates a valid response payload.

In case you’re not familiar with view handling, read the tutorial on how to render views in hapi first.

The Default 404 Error Handling in hapi

There’s a default error handling built into hapi and it’s just a JSON message send to the browser as plain text. Well, that’s absolutely fine if you’re relying on JSON responses.

default 404 error message in hapi

hapi default 404 error view

For web applications that actually render views in the browser, the default error handling is not sufficient. Read on to know what steps you need to take to have a more appropriate setup for your web app.

Create a Better 404 Route Handler

To handle 404 errors in your hapi app, add a single route that represents a last resort. This route will match all route paths that didn’t fit to any other route in your server.

hapi v17

  method: [ 'GET', 'POST' ],
  path: '/{any*}',
  handler: (request, h) => {
    const accept = request.headers.accept

    if (accept && accept.match(/json/)) {
      return Boom.notFound('Fuckity fuck, this resource isn’t available.')

    return h.view('404').code(404)

hapi v16

  method: [ 'GET', 'POST' ],
  path: '/{any*}',
  handler: (request, reply) => {
    const accept = request.raw.req.headers.accept

    // take priority: check header if there’s a JSON REST request
    if (accept && accept.match(/json/)) {
      return reply(Boom.notFound('Fuckity fuck, this resource isn’t available.'))


The defined route handler will be applied to GET and POST requests. If you need to handle any other method, add it to the list.

The route’s path needs to be a path parameter which will also handle routes that contain multiple forward slashes. Routes like http://your.domain/not/available/route will be caught as well and the any path parameter will have the value of not/available/route.

Within the route handler, differentiate between browser and REST requests. To reply requests that explicitly want JSON payload in response, you can use the regular expression to check whether the Accept request header contains the value of json.

Well, if you don’t need to handle any JSON requests, you can delete this part right away. Just keep in mind that this functionality can be added easily.

If there’s an accept request header available and it also matches the value of json, the response is handled with boom. boom will automatically create a proper JSON payload and set the HTTP status code to 404.

For requests from the browser, a view called 404 gets rendered and the status code 404 is explicitly set for the response.

That’s all the magic :) This route handler will catch all routes that don’t match any of your other routes within your hapi server. Because this route has the least restrictions for any paths and parameters, it’ll be called last by hapi.

Results: Web View and JSON Response

Of course the most interesting part is the result. The following screenshots illustrate the different responses depending on the request’s source.

404 web view response

custom 404 error handler and view

For requests from the browser, you want to keep the user in your website context and render a nice looking web view. Your page might look more solid with a navigation bar and footer ;-)

404 JSON response

custom 404 json error response

Requests from clients that want JSON in return should set the Accept header to application/json. In case of a 404 error, your handler will also keep the JSON format and respond properly with a JSON message containing the statusCode, error, and message fields. Also, the HTTP status code is properly set to 404.

Sample Implementation

We’ve published a sample implementation showing you the 404 handling over at GitHub. The code includes a very basic hapi server with just two routes: an index page and the 404. Every route besides the index will be caught by the 404 handler.

In case you want to see the big picture, just head over to the sample project on GitHub.


A proper 404 handling is something that doesn’t seem important in the first place. Actually, it’s absolutely fine to just have a very simple view or response handling for 404 errors. Just keep attention to how you’d feel if you’re visiting a route that isn’t available on a given website and there’s a techy, out of context error message presented as JSON.

Give your 404 page some love and take the opportunity to help users understand what happened and why this error occurs.

We’re happy to hear your thoughts and comments. Please don’t hesitate to use the comments below or find us on Twitter @futurestud_io. Let us know what you think!

Enjoy coding & make it rock!

Additional Resources

Explore the Library

Find interesting tutorials and solutions for your problems.