@@ -11,6 +11,19 @@ type RouteHandler<T = unknown> = (
1111 context : T
1212) => Promise < NextResponse | Response > | NextResponse | Response
1313
14+ /**
15+ * Reads a numeric `statusCode` (4xx or 5xx) off an Error so typed domain errors
16+ * (e.g. `WorkspaceAccessDeniedError`) can map to the correct HTTP status when
17+ * they bubble up unhandled instead of defaulting to 500.
18+ */
19+ function readTypedErrorStatus ( error : unknown ) : number | undefined {
20+ if ( ! ( error instanceof Error ) ) return undefined
21+ const status = ( error as { statusCode ?: unknown } ) . statusCode
22+ if ( typeof status !== 'number' ) return undefined
23+ if ( status < 400 || status >= 600 ) return undefined
24+ return status
25+ }
26+
1427/**
1528 * Wraps a Next.js API route handler with centralized error reporting.
1629 *
@@ -35,8 +48,21 @@ export function withRouteHandler<T>(handler: RouteHandler<T>): RouteHandler<T> {
3548 } catch ( error ) {
3649 const duration = Date . now ( ) - startTime
3750 const message = getErrorMessage ( error , 'Unknown error' )
38- logger . error ( 'Unhandled route error' , { duration, error : message } )
39- response = NextResponse . json ( { error : 'Internal server error' , requestId } , { status : 500 } )
51+ const typedStatus = readTypedErrorStatus ( error )
52+ if ( typedStatus !== undefined ) {
53+ if ( typedStatus >= 500 ) {
54+ logger . error ( 'Unhandled route error' , { duration, status : typedStatus , error : message } )
55+ } else {
56+ logger . warn ( 'Typed route error' , { duration, status : typedStatus , error : message } )
57+ }
58+ response = NextResponse . json ( { error : message , requestId } , { status : typedStatus } )
59+ } else {
60+ logger . error ( 'Unhandled route error' , { duration, error : message } )
61+ response = NextResponse . json (
62+ { error : 'Internal server error' , requestId } ,
63+ { status : 500 }
64+ )
65+ }
4066 response ?. headers ?. set ( 'x-request-id' , requestId )
4167 return response
4268 }
0 commit comments