( res: VercelResponse, error: any, statusCode: number )
| 90 | } |
| 91 | |
| 92 | export async function errorResponseWithStatusCode( |
| 93 | res: VercelResponse, |
| 94 | error: any, |
| 95 | statusCode: number |
| 96 | ): Promise<void> { |
| 97 | console.error('errorResponseWithStatusCode', error, statusCode); |
| 98 | Sentry.withScope(scope => { |
| 99 | if (error.details) { |
| 100 | scope.setExtra('details', error.details); |
| 101 | if (error.details.path) { |
| 102 | scope.addBreadcrumb({ |
| 103 | category: 'query-path', |
| 104 | message: error.details.path, |
| 105 | level: SEVERITY_DEBUG, |
| 106 | }); |
| 107 | } |
| 108 | } |
| 109 | if (error.causeMessage) { |
| 110 | scope.setExtra('cause', error.causeMessage); |
| 111 | } |
| 112 | if (error instanceof NotFoundError) { |
| 113 | // these are noisy and not actionable |
| 114 | } else if (error instanceof Error) { |
| 115 | Sentry.captureException(error); |
| 116 | } else if (error.message) { |
| 117 | // Sentry much prefers an Error object to a string/object |
| 118 | Sentry.captureException(new Error(error.message)); |
| 119 | } else { |
| 120 | // No idea what's going on here so at least get an error with a string in it |
| 121 | Sentry.captureException(new Error(JSON.stringify(error))); |
| 122 | } |
| 123 | }); |
| 124 | // We have to await this flush otherwise we exit before reporting to sentry |
| 125 | return Sentry.flush(awaitSentryFlushMs).then(() => { |
| 126 | const errObject = { |
| 127 | message: error.message || 'Unexpected error', |
| 128 | extensions: { |
| 129 | code: `${statusCode}`, |
| 130 | details: error.details || undefined, |
| 131 | }, |
| 132 | }; |
| 133 | res.status(statusCode).json(errObject); |
| 134 | }); |
| 135 | } |
| 136 | |
| 137 | function zodParserErrorResponse(res: VercelResponse, zodError: ZodError): void { |
| 138 | let msg = 'Invalid input'; |
no outgoing calls
no test coverage detected