From 07f670c23211a3b615d47877b430e1a6c0f0ac24 Mon Sep 17 00:00:00 2001 From: Joo-Byungho Date: Sun, 28 Dec 2025 18:40:31 +0900 Subject: [PATCH 1/3] fix: add HttpException handling in GraphQL error formatter --- src/common/exceptions/exception.constant.ts | 1 + src/common/exceptions/exception.format.ts | 9 +++++++++ src/common/exceptions/exception.util.ts | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/common/exceptions/exception.constant.ts b/src/common/exceptions/exception.constant.ts index e70f4f0..bbf84e2 100644 --- a/src/common/exceptions/exception.constant.ts +++ b/src/common/exceptions/exception.constant.ts @@ -10,6 +10,7 @@ export const GRAPHQL_ERROR_CODES = [ ]; export const PRESERVED_STATUS_CODES = [ + HttpStatus.BAD_REQUEST, HttpStatus.UNAUTHORIZED, HttpStatus.FORBIDDEN, ] as const; diff --git a/src/common/exceptions/exception.format.ts b/src/common/exceptions/exception.format.ts index c29df1b..ac975a8 100644 --- a/src/common/exceptions/exception.format.ts +++ b/src/common/exceptions/exception.format.ts @@ -4,6 +4,7 @@ import { GraphQLError } from 'graphql'; import { PRESERVED_STATUS_CODES } from './exception.constant'; import { + getHttpExceptionCode, isBaseException, isGraphqlOriginalError, isHttpException, @@ -26,6 +27,14 @@ const determineErrorCondition = (error: GraphQLError) => { }; } + if (isHttpException(error.originalError)) { + const status = error.originalError.getStatus(); + return { + errorStatus: status, + errorCode: getHttpExceptionCode(status), + }; + } + return { errorStatus: HttpStatus.INTERNAL_SERVER_ERROR, errorCode: 'INTERNAL_SERVER_ERROR', diff --git a/src/common/exceptions/exception.util.ts b/src/common/exceptions/exception.util.ts index 4938318..d7a375a 100644 --- a/src/common/exceptions/exception.util.ts +++ b/src/common/exceptions/exception.util.ts @@ -1,4 +1,4 @@ -import { HttpException } from '@nestjs/common'; +import { HttpException, HttpStatus } from '@nestjs/common'; import { GraphQLErrorExtensions } from 'graphql'; @@ -23,3 +23,7 @@ export const isBaseException = ( export const isHttpException = (error: unknown): error is HttpException => { return error instanceof HttpException; }; + +export const getHttpExceptionCode = (status: number): string => { + return HttpStatus[status] || 'HTTP_ERROR'; +}; From 7a7f7b1942ca4fba13cda595f590e2fc2bff7423 Mon Sep 17 00:00:00 2001 From: Joo-Byungho Date: Sun, 28 Dec 2025 18:40:45 +0900 Subject: [PATCH 2/3] fix: extract actual validation message from HttpException --- src/common/exceptions/exception.format.ts | 11 ++++++++++- src/common/exceptions/exception.util.ts | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/common/exceptions/exception.format.ts b/src/common/exceptions/exception.format.ts index ac975a8..1c4c806 100644 --- a/src/common/exceptions/exception.format.ts +++ b/src/common/exceptions/exception.format.ts @@ -5,6 +5,7 @@ import { GraphQLError } from 'graphql'; import { PRESERVED_STATUS_CODES } from './exception.constant'; import { getHttpExceptionCode, + getHttpExceptionMessage, isBaseException, isGraphqlOriginalError, isHttpException, @@ -84,6 +85,14 @@ const handleInternalServerError = ( } }; +const determineErrorMessage = (error: GraphQLError): string => { + if (isHttpException(error.originalError)) { + return getHttpExceptionMessage(error.originalError); + } + + return error.message; +}; + const formatError = ( error: GraphQLError, options: { @@ -104,7 +113,7 @@ const formatError = ( options.setHttpStatus(httpStatus); return { - message: error.message, + message: determineErrorMessage(error), locations: error.locations, path: error.path, extensions: { diff --git a/src/common/exceptions/exception.util.ts b/src/common/exceptions/exception.util.ts index d7a375a..d5a083b 100644 --- a/src/common/exceptions/exception.util.ts +++ b/src/common/exceptions/exception.util.ts @@ -27,3 +27,25 @@ export const isHttpException = (error: unknown): error is HttpException => { export const getHttpExceptionCode = (status: number): string => { return HttpStatus[status] || 'HTTP_ERROR'; }; + +export const getHttpExceptionMessage = (error: HttpException): string => { + const response = error.getResponse(); + + if (typeof response === 'string') { + return response; + } + + if (typeof response === 'object' && response !== null) { + const { message } = response as { message?: string | string[] }; + + if (Array.isArray(message)) { + return message.join(', '); + } + + if (typeof message === 'string') { + return message; + } + } + + return error.message; +}; From e7f725cad2f5061f25f657043c0590fe4e837258 Mon Sep 17 00:00:00 2001 From: Joo-Byungho Date: Sun, 28 Dec 2025 18:50:21 +0900 Subject: [PATCH 3/3] fix: fallback to error code when exception message template is empty --- src/common/exceptions/exception.factory.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/common/exceptions/exception.factory.ts b/src/common/exceptions/exception.factory.ts index 65a031a..6aace89 100644 --- a/src/common/exceptions/exception.factory.ts +++ b/src/common/exceptions/exception.factory.ts @@ -31,9 +31,8 @@ export const createException = () => { constructor(arg?: ExceptionParams) { super(statusCode, defaultMessage, code); - if (arg) { - this.message = composeExceptionMessage(defaultMessage, arg) as K; - } + const composed = composeExceptionMessage(defaultMessage, arg ?? {}); + this.message = (composed || code) as K; } }; };