cloudflare/cloudflared · error

Failed to proxy HTTP: %w

Error message

Failed to proxy HTTP: %w

What it means

In the HTTP/2 origin connection's ServeHTTP, requests typed TypeWebsocket or TypeHTTP are handed to the origin proxy via ProxyHTTP. Any error from proxying (origin unreachable, bad URL in ingress rule, TLS failure, streaming error) is wrapped as `Failed to proxy HTTP: %w` and logged/returned to the edge. It is the generic umbrella error for HTTP/websocket proxying failures on an http2 connection.

Source

Thrown at connection/http2.go:134

	}

	var requestErr error
	switch connType {
	case TypeControlStream:
		requestErr = c.controlStreamHandler.ServeControlStream(r.Context(), respWriter, c.connOptions.ConnectionOptions(), c.orchestrator)
		if requestErr != nil {
			c.controlStreamErr = requestErr
		}

	case TypeConfiguration:
		requestErr = c.handleConfigurationUpdate(respWriter, r)

	case TypeWebsocket, TypeHTTP:
		stripWebsocketUpgradeHeader(r)
		// Check for tracing on request
		tr := tracing.NewTracedHTTPRequest(r, c.connIndex, c.log)
		if err := originProxy.ProxyHTTP(respWriter, tr, connType == TypeWebsocket); err != nil {
			requestErr = fmt.Errorf("Failed to proxy HTTP: %w", err)
		}

	case TypeTCP:
		host, err := getRequestHost(r)
		if err != nil {
			requestErr = fmt.Errorf(`cloudflared received a warp-routing request with an empty host value: %w`, err)
			break
		}

		rws := NewHTTPResponseReadWriterAcker(respWriter, respWriter, r)
		requestErr = originProxy.ProxyTCP(r.Context(), rws, &TCPRequest{
			Dest:      host,
			CFRay:     FindCfRayHeader(r),
			LBProbe:   IsLBProbeRequest(r),
			CfTraceID: r.Header.Get(tracing.TracerContextName),
			ConnIndex: c.connIndex,
		})

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Check the wrapped error text for the root cause and verify the origin service is running and reachable at the URL in the ingress rule
  2. Verify `service:` in config.yml uses the correct scheme (http://, https://, or status: 200 for a hello-world)
  3. Test the origin directly: `curl -I http://localhost:8080` from the same host
  4. Inspect `cloudflared tunnel` logs for repeated failures; enable `--loglevel debug` for more detail

Example fix

# before (config.yml)
ingress:
  - hostname: app.example.com
    service: http:/localhost:8080
# after
ingress:
  - hostname: app.example.com
    service: http://localhost:8080
Defensive patterns

Strategy: retry

Validate before calling

// Verify origin reachability before starting the tunnel:
resp, err := http.Get("http://localhost:8080/health")
if err != nil { log.Fatalf("origin unreachable: %v", err) }
resp.Body.Close()

Try / catch

if strings.HasPrefix(err.Error(), "Failed to proxy HTTP:") {
    // inspect wrapped cause with errors.Unwrap / %w chain, then retry or alert
    log.Error().Err(err).Msg("origin proxy failure; check origin service and ingress service URL")
}

Prevention

When it happens

Trigger: originProxy.ProxyHTTP returns an error while serving an incoming edge request with connection type TypeHTTP or TypeWebsocket — e.g. dialing the origin service fails, the ingress rule URL is malformed, or the origin resets the connection mid-request.

Common situations: Local origin service not running or listening on the wrong port, ingress `service:` URL typos (http:// vs https://), origin TLS certificate issues, or websocket upgrades rejected by the origin.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/18c0e4d9351a5c61. Report an issue: GitHub.