diff --git a/lib/error-handler.js b/lib/error-handler.js index 0b9dbdbb99..cde82f8bae 100644 --- a/lib/error-handler.js +++ b/lib/error-handler.js @@ -65,13 +65,17 @@ function handleError (reply, error, cb) { return } - const result = func(error, reply.request, reply) - if (result !== undefined) { - if (result !== null && typeof result.then === 'function') { - wrapThenable(result, reply) - } else { - reply.send(result) + try { + const result = func(error, reply.request, reply) + if (result !== undefined) { + if (result !== null && typeof result.then === 'function') { + wrapThenable(result, reply) + } else { + reply.send(result) + } } + } catch (err) { + reply.send(err) } } diff --git a/lib/wrapThenable.js b/lib/wrapThenable.js index b746a62e92..abb75bdd03 100644 --- a/lib/wrapThenable.js +++ b/lib/wrapThenable.js @@ -39,6 +39,8 @@ function wrapThenable (thenable, reply) { // try-catch allow to re-throw error in error handler for async handler try { reply.send(err) + // The following should not happen + /* c8 ignore next 3 */ } catch (err) { reply.send(err) } diff --git a/test/500s.test.js b/test/500s.test.js index 3422fcfec4..3c915dba0a 100644 --- a/test/500s.test.js +++ b/test/500s.test.js @@ -188,3 +188,35 @@ test('cannot set childLoggerFactory after binding', t => { } }) }) + +test('catch synchronous errors', t => { + t.plan(3) + + const fastify = Fastify() + t.teardown(fastify.close.bind(fastify)) + + fastify.setErrorHandler((_, req, reply) => { + throw new Error('kaboom2') + }) + + fastify.post('/', function (req, reply) { + reply.send(new Error('kaboom')) + }) + + fastify.inject({ + method: 'POST', + url: '/', + headers: { + 'Content-Type': 'application/json' + }, + payload: JSON.stringify({ hello: 'world' }).substring(0, 5) + }, (err, res) => { + t.error(err) + t.equal(res.statusCode, 500) + t.same(res.json(), { + error: 'Internal Server Error', + message: 'kaboom2', + statusCode: 500 + }) + }) +}) diff --git a/test/types/request.test-d.ts b/test/types/request.test-d.ts index fd3359bab3..dfd4b78702 100644 --- a/test/types/request.test-d.ts +++ b/test/types/request.test-d.ts @@ -81,8 +81,8 @@ const getHandler: RouteHandler = function (request, _reply) { expectType['config']>(request.routeConfig) expectType['config']>(request.routeOptions.config) expectType(request.routeOptions.config) - expectType(request.routeSchema) - expectType(request.routeOptions.schema) + expectType(request.routeSchema) + expectType(request.routeOptions.schema) expectType(request.routeOptions.handler) expectType(request.routeOptions.url) diff --git a/types/request.d.ts b/types/request.d.ts index b1b82c6e61..b2e4e38ec5 100644 --- a/types/request.d.ts +++ b/types/request.d.ts @@ -31,7 +31,7 @@ export interface RequestRouteOptions; routeConfig: FastifyRequestContext['config']; - routeSchema: FastifySchema + routeSchema?: FastifySchema; // it is empty for 404 requests /** in order for this to be used the user should ensure they have set the attachValidation option. */ validationError?: Error & { validation: any; validationContext: string };