gofiber/fiber · error

proxy: parse upstream

Error message

proxy: parse upstream %q: %w

What it means

parseUpstream trims and normalizes the raw upstream string (defaulting to http:// if no scheme) then calls url.Parse. If url.Parse returns an error — typically for control characters, invalid percent-escapes, or malformed URLs — it is wrapped with the normalized raw value for diagnosis. This is the lowest-level parse failure, before scheme/host checks.

Solutions

  1. Inspect the quoted raw value in the message: it shows exactly what was parsed after trimming and scheme defaulting.
  2. Re-enter the upstream string as a clean ASCII value with no spaces or control characters.
  3. Validate upstreams at config load time and fail fast with a clear message rather than at request time.
  4. If upstreams come from user input, sanitize (reject control bytes, require valid percent-encoding) before passing to proxy.
  5. URL-encode any path components that legitimately contain special characters.

Example fix

// before: trailing space or control char in env
upstream := os.Getenv("UPSTREAM") // "http://svc:8080\r"

// after: trim and validate
upstream := strings.TrimSpace(os.Getenv("UPSTREAM"))
if _, err := url.Parse(upstream); err != nil { log.Fatalf("bad UPSTREAM: %v", err) }
Defensive patterns

Strategy: validation

Validate before calling

// Validate upstream strings at config load.
func validUpstream(raw string) error {
  if strings.TrimSpace(raw) == "" { return errors.New("empty upstream") }
  if !strings.Contains(raw, "://") { raw = "http://" + raw }
  _, err := url.Parse(raw)
  return err
}

Prevention

When it happens

Trigger: Configured upstream contains raw control bytes (e.g. a CR/LF injection in a config file), invalid percent-encoding like '%zz', unescaped spaces, or a stray bracket. Also triggered by user input forwarded as an upstream target without sanitization.

Common situations: Misformatted Balancer.Servers or proxy.Targets entry in config; env var with trailing whitespace or quotes that survive into url.Parse; a config-management tool that wrote a non-printable character; copy-paste from a rich-text source introducing smart quotes.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/47335b7579cfd67b. Report an issue: GitHub.

Appendix: source

Thrown at middleware/proxy/security.go:293

			}
		}
	}
}

// parseUpstream returns the parsed url.URL for raw. Hosts without an
// explicit scheme default to http:// to match the historical Balancer
// behavior where bare "host:port" entries were accepted.
func parseUpstream(raw string) (*url.URL, error) {
	raw = utils.TrimSpace(raw)
	if raw == "" {
		return nil, ErrUpstreamHostInvalid
	}
	if !strings.Contains(raw, "://") {
		raw = "http://" + raw
	}
	u, err := url.Parse(raw)
	if err != nil {
		return nil, fmt.Errorf("proxy: parse upstream %q: %w", raw, err)
	}
	return u, nil
}

// validateUpstream parses raw, enforces the scheme allowlist, and unless
// the policy permits private addresses, resolves the hostname and
// rejects responses that include any blocked address. Rejecting on a
// single blocked answer mitigates DNS rebinding attempts in which the
// resolver returns a mix of public and private IPs.
func validateUpstream(raw string, policy SecurityPolicy) (*url.URL, error) {
	u, err := parseUpstreamScheme(raw, policy)
	if err != nil {
		return nil, err
	}
	if policy.AllowPrivateIPs {
		return u, nil
	}
	if err := validateHostForSSRF(u.Hostname()); err != nil {

View on GitHub (pinned to a105acad6c)