air-verse/air · warning

proxy handler: bad form

Error message

proxy handler: bad form

What it means

proxyHandler must parse the incoming request's form data so it can re-encode the body when forwarding. If r.ParseForm fails (malformed query string or form body), the proxy responds with HTTP 500 and this fixed message.

Source

Thrown at runner/proxy.go:157

	page := buf.String()

	// the script will be injected before the end of the body tag. In case the tag is missing, the injection will be skipped with no error.
	body := strings.LastIndex(page, "</body>")
	if body == -1 {
		return page, decoded, nil
	}

	script := "<script>" + ProxyScript + "</script>"
	return page[:body] + script + page[body:], decoded, nil
}

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)

View on GitHub (pinned to 71ea1dee05)

Solutions

  1. URL-encode query parameters properly in the client (encodeURIComponent / url.Values.Encode)
  2. Fix malformed percent-escapes in the request URL (e.g. use %25 for a literal %)
  3. Reproduce the failing URL and check its query string with url.ParseRequestURI
  4. Send a JSON body with correct Content-Type instead of a form if that suits the API

Example fix

// before (client)
fetch('/api?q=100%')
// after
fetch('/api?q=' + encodeURIComponent('100%'))
Defensive patterns

Strategy: validation

Validate before calling

// validate outgoing URLs in the client
u, err := url.Parse(rawURL)
if err != nil || strings.Contains(u.RawQuery, "%") {
	// ensure every % is part of a valid escape
	if err != nil || regexp.MustCompile(`%(?![0-9A-Fa-f]{2})`).MatchString(u.RawQuery) {
		return fmt.Errorf("malformed query string: %q", rawURL)
	}
}

Try / catch

resp, err := http.Get(url)
if err != nil && resp != nil && resp.StatusCode == 500 {
	body, _ := io.ReadAll(resp.Body)
	if strings.Contains(string(body), "proxy handler: bad form") {
		// fix percent-encoding in the request URL/body
	}
}

Prevention

When it happens

Trigger: A client sends a request to the air proxy whose URL query string or application/x-www-form-urlencoded body is malformed (e.g. bad percent-encoding like `%zz`), causing http.Request.ParseForm to return an error.

Common situations: Frontend code building query strings with improperly escaped special characters (% not encoded as %25); manually constructed URLs with raw `#`, spaces, or broken percent-encoding; test tools sending deliberately bad forms.

Related errors


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