Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom error handler unable to check for instanceof ResponseValidationError #64

Open
nickramsbottom opened this issue Sep 14, 2023 · 4 comments

Comments

@nickramsbottom
Copy link

I am writing my own error handler for Fastify and want to intercept ResponseValidationErrors similar to the code example here: #26 (comment). I'm using TypeScript.

When I try to check for the error using error instanceof ResponseValidationError I get false.

error.name === 'ResponseValidationError' is true so it is an instance of ResponseValidationError:

this.name = 'ResponseValidationError';

Am I missing something here? If the name is set correctly I'd expect the instanceof check to work.

My overall goal is to respond normally on response validation errors and log instead of returning errors to the client.

Code to reproduce below.

import { FastifyInstance } from 'fastify'
import {
	ResponseValidationError,
	ZodTypeProvider,
} from 'fastify-type-provider-zod'
import z, { ZodError } from 'zod'

type Params = {
	id: string
}

export default async function routes(fastify: FastifyInstance) {
	fastify.get('/', async () => ({ hello: 'world' }))
	fastify.withTypeProvider<ZodTypeProvider>().get<{ Params: Params }>(
		'/session/:id',
		{
			schema: {
				params: z.object({
					id: z.string().max(5),
				}),
				response: {
					200: z.number(),
				},
			},
		},
		async (request, reply) => {
			const { id } = request.params
			reply.send({ hello: id })
		},
	)

	fastify.setErrorHandler(function (error, request, reply) {
		fastify.log.warn(error)
		console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
		if (error instanceof ZodError) {
			console.log('ZodError')
		}

		if (error instanceof ResponseValidationError) {
			console.log('ResponseValidationError')
		}

		if (error.name === 'ResponseValidationError') {
			console.log('name is ResponseValidationError')
		}

		if (error instanceof Error) {
			console.log('Error')
		}
		console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')

		reply.status(500).send({
			statusCode: 500,
			error: 'Failed successfully',
		})
	})
}
@kibertoad
Copy link
Collaborator

I'll add a typeguard for these cases

@nickramsbottom
Copy link
Author

@kibertoad am I missing something fundamental with how instanceof works with classes? It looks like it's creating an instance of the class I linked so I'd expect error instanceof ResponseValidationError to be true. I'm starting to doubt I understand what's going on!

@kibertoad
Copy link
Collaborator

@nickramsbottom instanceof is tricky in JavaScript, it is dependent on classes being from the same realm, see https://stackoverflow.com/questions/68564010/is-it-possible-several-javascript-realms-share-one-single-global-object

If you import a library A, and another library B imports a library A, and you use a class instantiated by library B using class from library A, there is a high chance they will be of a different realm, and won't pass instanceof check. for this reason I highly advise never to rely on instanceof for classes coming from external libraries, but use custom typeguards instead.

@nickramsbottom
Copy link
Author

@kibertoad Interesting! That's my something new learnt today, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants