gofiber/fiber · error

proxy: parse upstream %q: %w

Error message

proxy: parse upstream %q: %w

What it means

Returned by parseUpstream when url.Parse fails on the raw upstream string. Bare hosts without a scheme are first prefixed with http://, so this fires only when even that constructed URL is syntactically invalid.

Source

Thrown at middleware/proxy/security.go:297

			}
		}
	}
}

// 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 9a4c7e57fe)

Solutions

  1. Validate and sanitize the upstream string with net/url.Parse before configuring the proxy.
  2. Trim whitespace and reject strings with control characters.
  3. Construct upstream URLs from trusted components (scheme + host + port) rather than concatenating raw input.

Example fix

// before: passing raw config straight through
proxy.Do(ctx, cfg.UpstreamURL) // may be malformed

// after: pre-validate
u, err := url.Parse(strings.TrimSpace(cfg.UpstreamURL))
if err != nil {
    return fiber.NewError(fiber.StatusBadRequest, "bad upstream")
}
proxy.Do(ctx, u.String())
Defensive patterns

Strategy: validation

Validate before calling

// Validate the upstream URL parses before handing it to the proxy.
func validUpstream(raw string) (string, error) {
    raw = strings.TrimSpace(raw)
    if !strings.Contains(raw, "://") {
        raw = "http://" + raw
    }
    u, err := url.Parse(raw)
    if err != nil {
        return "", err
    }
    return u.String(), nil
}

Try / catch

if _, err := url.Parse(upstream); err != nil {
    return fiber.NewError(fiber.StatusBadRequest,
        "upstream URL is malformed")
}
return proxy.Do(c, upstream)

Prevention

When it happens

Trigger: Passing a malformed upstream to proxy.Do/Forward/Balancer, e.g. a string with illegal control characters, an invalid percent-encoding, or a scheme/authority that url.Parse rejects.

Common situations: User-controlled or config-supplied upstream URL with stray characters; unescaped spaces/control bytes; a typo like 'http//host'; copy-paste of a URL with backslashes or raw unicode.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/47335b7579cfd67b.json. Report an issue: GitHub.