{"record":{"id":"c7acf1fbdbfc48ba","repo":"air-verse/air","slug":"proxy-handler-unable-to-create-request","errorCode":null,"errorMessage":"proxy handler: unable to create request","messagePattern":"proxy handler: unable to create request","errorType":"http","errorClass":null,"httpStatus":500,"severity":"warning","filePath":"runner/proxy.go","lineNumber":168,"sourceCode":"\nfunc (p *Proxy) proxyHandler(w http.ResponseWriter, r *http.Request) {\n\tappURL := r.URL\n\tappURL.Scheme = \"http\"\n\tappURL.Host = fmt.Sprintf(\"localhost:%d\", p.config.AppPort)\n\n\tif err := r.ParseForm(); err != nil {\n\t\thttp.Error(w, \"proxy handler: bad form\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\tvar body io.Reader\n\tif len(r.Form) > 0 {\n\t\tbody = strings.NewReader(r.Form.Encode())\n\t} else {\n\t\tbody = r.Body\n\t}\n\treq, err := http.NewRequest(r.Method, appURL.String(), body)\n\tif err != nil {\n\t\thttp.Error(w, \"proxy handler: unable to create request\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Copy the headers from the original request\n\tfor name, values := range r.Header {\n\t\tfor _, value := range values {\n\t\t\treq.Header.Add(name, value)\n\t\t}\n\t}\n\tdelHopByHopHeaders(req.Header)\n\treq.Header.Set(\"X-Forwarded-For\", r.RemoteAddr)\n\n\t// set the via header\n\tviaHeaderValue := fmt.Sprintf(\"%s %s\", r.Proto, r.Host)\n\treq.Header.Set(\"Via\", viaHeaderValue)\n\n\t// air will restart the server. it may take a few seconds for it to start back up.\n\t// therefore, we retry until the server becomes available or this retry loop exits with an error.","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/air-verse/air/blob/71ea1dee05248122ed22b5870c7fb20a90d80ddd/runner/proxy.go#L150-L186","documentation":"After parsing the form, proxyHandler builds a new outbound http.NewRequest to forward the request to the app on AppPort. If constructing that request fails (invalid method, unparseable URL, unsupported body type), the proxy replies with HTTP 500 and this message.","triggerScenarios":"proxyHandler calls http.NewRequest(r.Method, appURL.String(), body) and it errors — typically an invalid HTTP method token from the client or an appURL that fails url.Parse (app_port config producing an invalid host string).","commonSituations":"Clients sending requests with malformed/custom method tokens; app_port set to a value that produces an invalid URL (e.g. out-of-range port with weird formatting); exotic body types breaking NewRequest's io.Reader handling.","solutions":["Verify `app_port` in .air.toml is a plain valid TCP port (1-65535)","Check what method the client is sending — use a standard HTTP verb (GET/POST/...)","Enable air's proxy debug logs and inspect the incoming request line","Reproduce with curl using a standard method to confirm the proxy itself is healthy"],"exampleFix":"// before (.air.toml)\napp_port = \"http://localhost:3000\"  // invalid\n// after\napp_port = 3000","handlingStrategy":"validation","validationCode":"// ensure app_port yields a valid URL\nu := \"http://localhost:\" + strconv.Itoa(appPort)\nif _, err := url.Parse(u); err != nil {\n\treturn fmt.Errorf(\"invalid app_port %d: %w\", appPort, err)\n}","typeGuard":null,"tryCatchPattern":"resp, err := client.Do(req)\nif err != nil && resp != nil && resp.StatusCode == 500 {\n\tb, _ := io.ReadAll(resp.Body)\n\tif strings.Contains(string(b), \"unable to create request\") {\n\t\t// check HTTP verb and app_port config\n\t}\n}","preventionTips":["Keep app_port a plain integer port (1-65535) in .air.toml","Use standard HTTP methods only in clients targeting the proxy","Validate proxy requests with curl before debugging exotic clients","Re-check app_port after renaming services/ports"],"tags":["proxy","http","request"],"backgroundTag":"invalid-http-request-construction","analyzedSha":"71ea1dee05248122ed22b5870c7fb20a90d80ddd","analyzedAt":"2026-08-31T20:27:54.676Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}