air-verse/air · warning

proxy handler: unable to create request

Error message

proxy handler: unable to create request

What it means

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.

Source

Thrown at runner/proxy.go:168

func (p *Proxy) proxyHandler(w http.ResponseWriter, r *http.Request) {
	appURL := r.URL
	appURL.Scheme = "http"
	appURL.Host = fmt.Sprintf("localhost:%d", p.config.AppPort)

	if err := r.ParseForm(); err != nil {
		http.Error(w, "proxy handler: bad form", http.StatusInternalServerError)
		return
	}
	var body io.Reader
	if len(r.Form) > 0 {
		body = strings.NewReader(r.Form.Encode())
	} else {
		body = r.Body
	}
	req, err := http.NewRequest(r.Method, appURL.String(), body)
	if err != nil {
		http.Error(w, "proxy handler: unable to create request", http.StatusInternalServerError)
		return
	}

	// Copy the headers from the original request
	for name, values := range r.Header {
		for _, value := range values {
			req.Header.Add(name, value)
		}
	}
	delHopByHopHeaders(req.Header)
	req.Header.Set("X-Forwarded-For", r.RemoteAddr)

	// set the via header
	viaHeaderValue := fmt.Sprintf("%s %s", r.Proto, r.Host)
	req.Header.Set("Via", viaHeaderValue)

	// air will restart the server. it may take a few seconds for it to start back up.
	// therefore, we retry until the server becomes available or this retry loop exits with an error.

View on GitHub (pinned to 71ea1dee05)

Solutions

  1. Verify `app_port` in .air.toml is a plain valid TCP port (1-65535)
  2. Check what method the client is sending — use a standard HTTP verb (GET/POST/...)
  3. Enable air's proxy debug logs and inspect the incoming request line
  4. Reproduce with curl using a standard method to confirm the proxy itself is healthy

Example fix

// before (.air.toml)
app_port = "http://localhost:3000"  // invalid
// after
app_port = 3000
Defensive patterns

Strategy: validation

Validate before calling

// ensure app_port yields a valid URL
u := "http://localhost:" + strconv.Itoa(appPort)
if _, err := url.Parse(u); err != nil {
	return fmt.Errorf("invalid app_port %d: %w", appPort, err)
}

Try / catch

resp, err := client.Do(req)
if err != nil && resp != nil && resp.StatusCode == 500 {
	b, _ := io.ReadAll(resp.Body)
	if strings.Contains(string(b), "unable to create request") {
		// check HTTP verb and app_port config
	}
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of air-verse/air@71ea1dee05 (2026-08-31). Data as JSON: /api/errors/c7acf1fbdbfc48ba. Report an issue: GitHub.