{"record":{"id":"bea2231fb437c474","repo":"plandex-ai/plandex","slug":"error-creating-request-for-proxy","errorCode":null,"errorMessage":"Error creating request for proxy","messagePattern":"Error creating request for proxy","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/proxy_helper.go","lineNumber":66,"sourceCode":"\t\tproxyUrl := fmt.Sprintf(\"http://%s:%s/plans/%s/%s/%s\", modelStream.InternalIp, os.Getenv(\"PORT\"), planId, branch, method)\n\t\tproxyUrl += \"?proxy=true\"\n\n\t\tlog.Printf(\"Proxy url: %s\\n\", proxyUrl)\n\t\tproxyRequest(w, r, proxyUrl)\n\t\treturn\n\t}\n}\n\nfunc proxyRequest(w http.ResponseWriter, originalRequest *http.Request, url string) {\n\tclient := &http.Client{\n\t\tTimeout: time.Second * 10,\n\t}\n\n\t// Create a new request based on the original request\n\treq, err := http.NewRequestWithContext(originalRequest.Context(), originalRequest.Method, url, originalRequest.Body)\n\tif err != nil {\n\t\tlog.Printf(\"Error creating request for proxy: %v\\n\", err)\n\t\thttp.Error(w, \"Error creating request for proxy\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Copy the headers from the original request to the new request\n\tfor name, headers := range originalRequest.Header {\n\t\tfor _, h := range headers {\n\t\t\treq.Header.Add(name, h)\n\t\t}\n\t}\n\n\t// Copy the body from the original request to the new request if it's a POST or PUT\n\tif originalRequest.Method == http.MethodPost || originalRequest.Method == http.MethodPut {\n\t\treq.Body = originalRequest.Body\n\t}\n\n\t// Make the request\n\tresp, err := client.Do(req)\n\tif err != nil {","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/proxy_helper.go#L48-L84","documentation":"proxyRequest builds an outbound http.NewRequestWithContext to clone the incoming request and forward it to the instance IP hosting the plan. If that construction fails, the handler returns HTTP 500 \"Error creating request for proxy\". http.NewRequestWithContext errors on an invalid URL or an unparsable method — almost always a malformed proxy URL.","triggerScenarios":"modelStream.InternalIp empty or malformed, producing a bad URL like \"http://:8080/plans/...\"; planId/branch/method containing characters that break URL formatting (spaces, slashes, control chars); os.Getenv(\"PORT\") empty yielding an invalid host:port; context already canceled passed to NewRequestWithContext (rare).","commonSituations":"Internal IP not set on the stream row (registration bug); un-encoded path segments from user input interpolated into the URL; PORT env var unset in a new deployment; IPv6 or hostname with scheme accidentally stored in InternalIp.","solutions":["Read the server log for the exact NewRequestWithContext error — it names the malformed URL.","Log/validate the composed proxyUrl before creating the request; url.Parse it to catch malformed pieces.","Ensure InternalIp is a bare IP/host set during stream registration; reject empty values earlier.","Use url.PathEscape for planId/branch/method path segments and validate PORT is set at startup.","Verify with url.Parse(proxyUrl) in tests that all lifecycle paths produce valid URLs."],"exampleFix":"// before\nproxyUrl := fmt.Sprintf(\"http://%s:%s/plans/%s/%s/%s\", modelStream.InternalIp, os.Getenv(\"PORT\"), planId, branch, method)\nreq, err := http.NewRequestWithContext(originalRequest.Context(), originalRequest.Method, url, originalRequest.Body)\n// after\nif modelStream.InternalIp == \"\" {\n    http.Error(w, \"Internal IP missing for plan stream\", http.StatusBadGateway)\n    return\n}\nport := os.Getenv(\"PORT\")\nif port == \"\" { port = \"8080\" }\nproxyUrl := fmt.Sprintf(\"http://%s:%s/plans/%s/%s/%s\",\n    modelStream.InternalIp, port,\n    url.PathEscape(planId), url.PathEscape(branch), url.PathEscape(method))\nif _, err := url.Parse(proxyUrl); err != nil {\n    http.Error(w, \"Invalid proxy URL\", http.StatusBadGateway)\n    return\n}\nreq, err := http.NewRequestWithContext(originalRequest.Context(), originalRequest.Method, proxyUrl, originalRequest.Body)","handlingStrategy":"validation","validationCode":"// server-side: validate URL parts before building the request\nif modelStream.InternalIp == \"\" || os.Getenv(\"PORT\") == \"\" {\n    http.Error(w, \"Proxy target not configured\", http.StatusBadGateway)\n    return\n}\nif _, err := url.Parse(fmt.Sprintf(\"http://%s:%s\", modelStream.InternalIp, os.Getenv(\"PORT\"))); err != nil {\n    http.Error(w, \"Invalid proxy target\", http.StatusBadGateway)\n    return\n}","typeGuard":null,"tryCatchPattern":"// caller of the proxied endpoint\ntry {\n  const res = await fetch(`/plans/${planId}/${branch}/connect`);\n  if (res.status === 500) console.error('Proxy misconfigured — check server logs for URL error');\n} catch (e) { console.error(e); }","preventionTips":["Validate InternalIp and PORT at stream registration time, not at proxy time.","Escape all path segments with url.PathEscape before interpolation.","Fail fast on missing required env vars (PORT) at startup.","Add unit tests asserting the composed proxyUrl parses for all lifecycle paths."],"tags":["http-500","proxy","url","request-creation"],"backgroundTag":"invalid-proxy-url","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}