From ca03ee8c79b33d0026185a20e5298365f25ad0b2 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Sun, 30 Aug 2026 04:46:24 +0000 Subject: [PATCH] Fix -ui-dev serving 502 for every page The dev-mode reverse proxy was built with NewSingleHostReverseProxy, which sets Director, and then had Rewrite assigned on top of it. ReverseProxy accepts exactly one of the two: with both set, ServeHTTP hands the request straight to the error handler and returns http: proxy error: ReverseProxy must have exactly one of Director or Rewrite set so every non-/api request under -ui-dev answered 502 instead of reaching the vite dev server. Running the UI against a live backend that way has never worked. Building the proxy from Rewrite alone keeps the intended behaviour -- Rewrite is the newer API and is what the SetURL/Host lines were written against -- and drops the Director that was only ever an artifact of the constructor. Nothing outside dev mode is affected: the branch is reached only when -ui-dev is passed, which is why the whole test suite and CI stayed green either way -- and why this carries no test of its own. The regression test for it arrives with the libs/services test suite on comstud/ui-multi-server; to check it by hand, run the UI dev server and start rotom-ng with -ui-dev, which serves pages instead of 502s. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AXB8suZYfpYZsSaoEps67m --- libs/services/web_server.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libs/services/web_server.go b/libs/services/web_server.go index 73c3860..2ab4460 100644 --- a/libs/services/web_server.go +++ b/libs/services/web_server.go @@ -86,10 +86,14 @@ func (s *WebServer) SetupRoutes(r *gin.Engine) error { s.logger.LogAttrs(context.Background(), slog.LevelInfo, "setting up HTTP server routes to proxy to UI dev server") target, _ := url.Parse("http://localhost:4199") - proxy := httputil.NewSingleHostReverseProxy(target) - proxy.Rewrite = func(pr *httputil.ProxyRequest) { - pr.SetURL(target) - pr.Out.Host = target.Host + // Built with Rewrite alone rather than from NewSingleHostReverseProxy: + // that constructor sets Director, and ReverseProxy refuses to serve + // anything when both are set, which turned every page into a 502. + proxy := &httputil.ReverseProxy{ + Rewrite: func(pr *httputil.ProxyRequest) { + pr.SetURL(target) + pr.Out.Host = target.Host + }, } r.NoRoute(func(c *gin.Context) {