Skip to content

Commit 4efd7ae

Browse files
authored
feat: add error handling for FetchError (#1634)
1 parent f7ade59 commit 4efd7ae

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

server/utils/error-handler.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isError, createError } from 'h3'
2+
import { FetchError } from 'ofetch'
23
import * as v from 'valibot'
34
import type { ErrorOptions } from '#shared/types/error'
45

@@ -18,6 +19,14 @@ export function handleApiError(error: unknown, fallback: ErrorOptions): never {
1819
throw error
1920
}
2021

22+
if (error instanceof FetchError && error.statusCode) {
23+
throw createError({
24+
statusCode: error.statusCode,
25+
statusMessage: error.statusMessage,
26+
message: error.message,
27+
})
28+
}
29+
2130
// Handle Valibot validation errors
2231
if (v.isValiError(error)) {
2332
throw createError({

test/unit/server/utils/error-handler.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, expect, it } from 'vitest'
22
import { createError } from 'h3'
3+
import { FetchError } from 'ofetch'
34
import * as v from 'valibot'
45
import { handleApiError } from '../../../../server/utils/error-handler'
56

@@ -44,4 +45,34 @@ describe('handleApiError', () => {
4445
expect.objectContaining({ statusCode: 503, message: 'Service unavailable' }),
4546
)
4647
})
48+
49+
describe('FetchError handling', () => {
50+
it('propagates the upstream statusCode from a FetchError', () => {
51+
const fetchErr = new FetchError('Not Found')
52+
fetchErr.statusCode = 404
53+
fetchErr.statusMessage = 'Not Found'
54+
55+
expect(() => handleApiError(fetchErr, fallback)).toThrow(
56+
expect.objectContaining({ statusCode: 404, message: 'Not Found' }),
57+
)
58+
})
59+
60+
it('propagates a 503 statusCode from a FetchError', () => {
61+
const fetchErr = new FetchError('Service Unavailable')
62+
fetchErr.statusCode = 503
63+
fetchErr.statusMessage = 'Service Unavailable'
64+
65+
expect(() => handleApiError(fetchErr, fallback)).toThrow(
66+
expect.objectContaining({ statusCode: 503 }),
67+
)
68+
})
69+
70+
it('falls through to the generic fallback when FetchError has no statusCode', () => {
71+
const fetchErr = new FetchError('Network error')
72+
73+
expect(() => handleApiError(fetchErr, { message: 'Bad gateway', statusCode: 502 })).toThrow(
74+
expect.objectContaining({ statusCode: 502, message: 'Bad gateway' }),
75+
)
76+
})
77+
})
4778
})

0 commit comments

Comments
 (0)