There are two simple solutions:
1. Use server.ext('onPreResponse' ...
As @Clarkie noted, a common way to catch all the errors in your Hapi application is to use 'onPreResponse' .
We wrote a Hapi plugin that does just that: https://www.npmjs.com/package/hapi-error
As usual, it has:

And it allows you to define your own error pages in 3 easy steps.
1. Install the plugin from npm:
npm install hapi-error
2. Include the plugin in the Hapi project
Enable the plugin when you register on your server:
See: /example/server_example.js for a simple example.
3. Make sure you have a view called error_template
Note: the hapi-error plugin expects you to use Vision (the standard library for rendering views for Hapi applications) which allows you to use Handlebars, Jade, React, etc. for your templates.
Your error_template.html (or error_template.ext error_template.jsx ) should use 3 variables that it will pass:
errorTitle - the error tile generated by HapistatusCode - * HTTP statusCode sent to the client, for example: 404 (not found)errorMessage - error message for a person
see /example/error_template.html for an example
What is it!

2. Use failAction

We added a failAction that uses register_handler so that registration-form.html displayed with any input validation error message (until it is sent with valid data)
{ method: '*', path: '/register', config: { validate: { payload : register_fields, failAction: register_handler // register_handler is dual-purpose (see below!) } }, handler: register_handler }
register_handler :
function register_handler(request, reply, source, error) { // show the registration form until its submitted correctly if(!request.payload || request.payload && error) { var errors, values; // return empty if not set. if(error && error.data) { // means the handler is dual-purpose errors = extract_validation_error(error); // the error field + message values = return_form_input_values(error); // avoid wiping form data } return reply.view('registration-form', { title : 'Please Register ' + request.server.version, error : errors, // error object used in html template values : values // (escaped) values displayed in form inputs }).code(error ? 400 : 200); // HTTP status code depending on error } else { // once successful, show welcome message! return reply.view('welcome-message', { name : validator.escape(request.payload.name), email : validator.escape(request.payload.email) }) } }
See: server.js : 57 for the full file.
Where extract_validation_error(error) and return_form_input_values(error) are helper functions defined inside server.js (but will be divided into reusable view helpers) that save our lean handler function.
When we submit the form without any required fields, we see:
<T411>

We also use https://github.com/chriso/validator.js to mitigate the scripts for multiple sites vulnerability:

And display a welcome message about successful registration: 
Conclusion
We believe that reusing the handler function as failAction saves the code associated with this route / action in one place whereas server.ext('onPreResponse' ... (with the appropriate initial inspection) introduces “hooks”, which may be the source confusion (when the application has many such hooks ...)
#YMMV
Let us know what you think! 