From e5ae816ab66cf2cd6ca2d3bc344ae753b5679083 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 25 Jun 2026 17:58:25 +0000 Subject: [PATCH 1/2] Suppress handled API client errors --- src/app/api/core/utils/withErrorHandler.ts | 5 ++- .../api/tests/utils/withErrorHandler.test.ts | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/app/api/core/utils/withErrorHandler.ts b/src/app/api/core/utils/withErrorHandler.ts index 62bc3f3bb..45a27213a 100644 --- a/src/app/api/core/utils/withErrorHandler.ts +++ b/src/app/api/core/utils/withErrorHandler.ts @@ -37,7 +37,6 @@ export const withErrorHandler = (handler: RequestHandler): RequestHandler => { if (error instanceof ZodError) { formattedError = error.format() as ZodFormattedError } - console.error(formattedError) // Default staus and message for JSON error response let status: number = (error as StatusableError).status || httpStatus.BAD_REQUEST @@ -65,6 +64,10 @@ export const withErrorHandler = (handler: RequestHandler): RequestHandler => { } } + if (status >= httpStatus.INTERNAL_SERVER_ERROR) { + console.error(formattedError) + } + return NextResponse.json({ error: message, errors }, { status }) } } diff --git a/src/app/api/tests/utils/withErrorHandler.test.ts b/src/app/api/tests/utils/withErrorHandler.test.ts index 13ba4c5c0..2d6e37a94 100644 --- a/src/app/api/tests/utils/withErrorHandler.test.ts +++ b/src/app/api/tests/utils/withErrorHandler.test.ts @@ -13,12 +13,18 @@ jest.mock('@/utils/CopilotAPI', () => ({ describe('withErrorHandler util', () => { let req: NextRequest + let consoleErrorSpy: jest.SpyInstance beforeEach(() => { jest.clearAllMocks() + consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined) req = buildNextRequest(`/?token=iu-token`) }) + afterEach(() => { + consoleErrorSpy.mockRestore() + }) + it('catches and builds proper response for APIError', async () => { const handler = async (_req: NextRequest, _params: any) => { throw new APIError(httpStatus.UNAUTHORIZED, 'Please provide a valid token') @@ -28,6 +34,7 @@ describe('withErrorHandler util', () => { const response = await nextResponse.json() expect(response.error).toBe('Please provide a valid token') expect(nextResponse.status).toBe(httpStatus.UNAUTHORIZED) + expect(consoleErrorSpy).not.toHaveBeenCalled() }) it('catches and builds proper response for ZodError', async () => { @@ -41,6 +48,7 @@ describe('withErrorHandler util', () => { expect(response.error[0].expected).toBe('string') expect(response.error[0].received).toBe('number') expect(nextResponse.status).toBe(httpStatus.UNPROCESSABLE_ENTITY) + expect(consoleErrorSpy).not.toHaveBeenCalled() }) it('catches and builds proper response for CopilotApiError', async () => { @@ -52,6 +60,40 @@ describe('withErrorHandler util', () => { const response = await nextResponse.json() expect(response.error).toBe('Please provide a valid token') expect(nextResponse.status).toBe(httpStatus.UNAUTHORIZED) + expect(consoleErrorSpy).not.toHaveBeenCalled() + }) + + it('catches and builds proper response for Copilot SDK style ApiError', async () => { + const error = new Error('Not Found') as Error & { + status: number + body: { message: string } + } + error.name = 'ApiError' + error.status = httpStatus.NOT_FOUND + error.body = { message: 'Not Found' } + + const handler = async (_req: NextRequest, _params: any) => { + throw error + } + + const nextResponse = await withErrorHandler(handler)(req, null) + const response = await nextResponse.json() + expect(response.error).toBe('Not Found') + expect(nextResponse.status).toBe(httpStatus.NOT_FOUND) + expect(consoleErrorSpy).not.toHaveBeenCalled() + }) + + it('logs server errors while returning the standardized response', async () => { + const error = new APIError(httpStatus.INTERNAL_SERVER_ERROR, 'Unexpected failure') + const handler = async (_req: NextRequest, _params: any) => { + throw error + } + + const nextResponse = await withErrorHandler(handler)(req, null) + const response = await nextResponse.json() + expect(response.error).toBe('Unexpected failure') + expect(nextResponse.status).toBe(httpStatus.INTERNAL_SERVER_ERROR) + expect(consoleErrorSpy).toHaveBeenCalledWith(error) }) it('returns proper response if no errors are encountered', async () => { @@ -63,5 +105,6 @@ describe('withErrorHandler util', () => { const response = await nextResponse.json() expect(response.message).toBe('Yay!') expect(nextResponse.status).toBe(httpStatus.OK) + expect(consoleErrorSpy).not.toHaveBeenCalled() }) }) From 7bd6da045a986022b25055fc6981e646ec8edaa7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 25 Jun 2026 17:59:13 +0000 Subject: [PATCH 2/2] Align error handler Zod test --- src/app/api/tests/utils/withErrorHandler.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/api/tests/utils/withErrorHandler.test.ts b/src/app/api/tests/utils/withErrorHandler.test.ts index 2d6e37a94..76406ab82 100644 --- a/src/app/api/tests/utils/withErrorHandler.test.ts +++ b/src/app/api/tests/utils/withErrorHandler.test.ts @@ -45,8 +45,7 @@ describe('withErrorHandler util', () => { const nextResponse = await withErrorHandler(handler)(req, null) const response = await nextResponse.json() - expect(response.error[0].expected).toBe('string') - expect(response.error[0].received).toBe('number') + expect(response.error).toBe('Expected string, received number') expect(nextResponse.status).toBe(httpStatus.UNPROCESSABLE_ENTITY) expect(consoleErrorSpy).not.toHaveBeenCalled() })