diff --git a/server/utils/error-handler.ts b/server/utils/error-handler.ts index 2afeda853..8ba47ea31 100644 --- a/server/utils/error-handler.ts +++ b/server/utils/error-handler.ts @@ -1,4 +1,5 @@ import { isError, createError } from 'h3' +import { FetchError } from 'ofetch' import * as v from 'valibot' import type { ErrorOptions } from '#shared/types/error' @@ -18,6 +19,14 @@ export function handleApiError(error: unknown, fallback: ErrorOptions): never { throw error } + if (error instanceof FetchError && error.statusCode) { + throw createError({ + statusCode: error.statusCode, + statusMessage: error.statusMessage, + message: error.message, + }) + } + // Handle Valibot validation errors if (v.isValiError(error)) { throw createError({ diff --git a/test/unit/server/utils/error-handler.spec.ts b/test/unit/server/utils/error-handler.spec.ts index 79024132f..262063628 100644 --- a/test/unit/server/utils/error-handler.spec.ts +++ b/test/unit/server/utils/error-handler.spec.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'vitest' import { createError } from 'h3' +import { FetchError } from 'ofetch' import * as v from 'valibot' import { handleApiError } from '../../../../server/utils/error-handler' @@ -44,4 +45,34 @@ describe('handleApiError', () => { expect.objectContaining({ statusCode: 503, message: 'Service unavailable' }), ) }) + + describe('FetchError handling', () => { + it('propagates the upstream statusCode from a FetchError', () => { + const fetchErr = new FetchError('Not Found') + fetchErr.statusCode = 404 + fetchErr.statusMessage = 'Not Found' + + expect(() => handleApiError(fetchErr, fallback)).toThrow( + expect.objectContaining({ statusCode: 404, message: 'Not Found' }), + ) + }) + + it('propagates a 503 statusCode from a FetchError', () => { + const fetchErr = new FetchError('Service Unavailable') + fetchErr.statusCode = 503 + fetchErr.statusMessage = 'Service Unavailable' + + expect(() => handleApiError(fetchErr, fallback)).toThrow( + expect.objectContaining({ statusCode: 503 }), + ) + }) + + it('falls through to the generic fallback when FetchError has no statusCode', () => { + const fetchErr = new FetchError('Network error') + + expect(() => handleApiError(fetchErr, { message: 'Bad gateway', statusCode: 502 })).toThrow( + expect.objectContaining({ statusCode: 502, message: 'Bad gateway' }), + ) + }) + }) })