| import { logger } from '@librechat/data-schemas'; |
| import { ErrorTypes } from 'librechat-data-provider'; |
| import type { NextFunction, Request, Response } from 'express'; |
| import type { MongoServerError, ValidationError, CustomError } from '~/types'; |
|
|
| const handleDuplicateKeyError = (err: MongoServerError, res: Response) => { |
| logger.warn('Duplicate key error: ' + (err.errmsg || err.message)); |
| const field = err.keyValue ? `${JSON.stringify(Object.keys(err.keyValue))}` : 'unknown'; |
| const code = 409; |
| res |
| .status(code) |
| .send({ messages: `An document with that ${field} already exists.`, fields: field }); |
| }; |
|
|
| const handleValidationError = (err: ValidationError, res: Response) => { |
| logger.error('Validation error:', err.errors); |
| const errorMessages = Object.values(err.errors).map((el) => el.message); |
| const fields = `${JSON.stringify(Object.values(err.errors).map((el) => el.path))}`; |
| const code = 400; |
| const messages = |
| errorMessages.length > 1 |
| ? `${JSON.stringify(errorMessages.join(' '))}` |
| : `${JSON.stringify(errorMessages)}`; |
|
|
| res.status(code).send({ messages, fields }); |
| }; |
|
|
| |
| function isValidationError(err: unknown): err is ValidationError { |
| return err !== null && typeof err === 'object' && 'name' in err && err.name === 'ValidationError'; |
| } |
|
|
| |
| function isMongoServerError(err: unknown): err is MongoServerError { |
| return err !== null && typeof err === 'object' && 'code' in err && err.code === 11000; |
| } |
|
|
| |
| function isCustomError(err: unknown): err is CustomError { |
| return err !== null && typeof err === 'object' && 'statusCode' in err && 'body' in err; |
| } |
|
|
| export const ErrorController = ( |
| err: Error | CustomError, |
| req: Request, |
| res: Response, |
| next: NextFunction, |
| ): Response | void => { |
| try { |
| if (!err) { |
| return next(); |
| } |
| const error = err as CustomError; |
|
|
| if ( |
| (error.message === ErrorTypes.AUTH_FAILED || error.code === ErrorTypes.AUTH_FAILED) && |
| req.originalUrl && |
| req.originalUrl.includes('/oauth/') && |
| req.originalUrl.includes('/callback') |
| ) { |
| const domain = process.env.DOMAIN_CLIENT || 'http://localhost:3080'; |
| return res.redirect(`${domain}/login?redirect=false&error=${ErrorTypes.AUTH_FAILED}`); |
| } |
|
|
| if (isValidationError(error)) { |
| return handleValidationError(error, res); |
| } |
|
|
| if (isMongoServerError(error)) { |
| return handleDuplicateKeyError(error, res); |
| } |
|
|
| if (isCustomError(error) && error.statusCode && error.body) { |
| return res.status(error.statusCode).send(error.body); |
| } |
|
|
| logger.error('ErrorController => error', err); |
| return res.status(500).send('An unknown error occurred.'); |
| } catch (processingError) { |
| logger.error('ErrorController => processing error', processingError); |
| return res.status(500).send('Processing error in ErrorController.'); |
| } |
| }; |
|
|