@@ -46,11 +46,33 @@ export class HttpProxyMiddleware<TReq, TRes> {
4646 // https://github.com/Microsoft/TypeScript/wiki/'this'-in-TypeScript#red-flags-for-this
4747 public middleware : RequestHandler = ( async ( req , res , next ?) => {
4848 if ( this . shouldProxy ( this . proxyOptions . pathFilter , req ) ) {
49+ let activeProxyOptions : Options < TReq , TRes > ;
4950 try {
50- const activeProxyOptions = await this . prepareProxyRequest ( req ) ;
51+ // Preparation Phase: Apply router and path rewriter.
52+ activeProxyOptions = await this . prepareProxyRequest ( req ) ;
53+
54+ // [Smoking Gun] httpxy is inconsistent with error handling:
55+ // 1. If target is missing (here), it emits 'error' but returns a boolean (bypassing our catch/next).
56+ // 2. If a network error occurs (in proxy.web), it rejects the promise but SKIPS emitting 'error'.
57+ // We manually throw here to force Case 1 into the catch block so next(err) is called for Express.
58+ if ( ! activeProxyOptions . target && ! activeProxyOptions . forward ) {
59+ throw new Error ( 'Must provide a proper URL as target' ) ;
60+ }
61+ } catch ( err ) {
62+ next ?.( err ) ;
63+ return ;
64+ }
65+
66+ try {
67+ // Proxying Phase: Handle the actual web request.
5168 debug ( `proxy request to target: %O` , activeProxyOptions . target ) ;
52- this . proxy . web ( req , res , activeProxyOptions ) ;
69+ await this . proxy . web ( req , res , activeProxyOptions ) ;
5370 } catch ( err ) {
71+ // Manually emit 'error' event because httpxy's promise-based API does not emit it automatically.
72+ // This is crucial for backward compatibility with HPM plugins (like error-response-plugin)
73+ // and custom listeners registered via the 'on: { error: ... }' option.
74+ this . proxy . emit ( 'error' , err , req , res , activeProxyOptions . target ) ;
75+
5476 next ?.( err ) ;
5577 }
5678 } else {
@@ -105,7 +127,7 @@ export class HttpProxyMiddleware<TReq, TRes> {
105127 try {
106128 if ( this . shouldProxy ( this . proxyOptions . pathFilter , req ) ) {
107129 const activeProxyOptions = await this . prepareProxyRequest ( req ) ;
108- this . proxy . ws ( req , socket , activeProxyOptions , head ) ;
130+ await this . proxy . ws ( req , socket , activeProxyOptions , head ) ;
109131 debug ( 'server upgrade event received. Proxying WebSocket' ) ;
110132 }
111133 } catch ( err ) {
0 commit comments