slimtoolkit/slim · error

dialing backend: %v

Error message

dialing backend: %v

What it means

After building the FastCGI environment, RoundTrip dials the FastCGI backend at network/address (defaulting to tcp + r.URL.Host) with the configured dial timeout. A dial failure is wrapped as "dialing backend: %v". This is the classic 'cannot reach the FastCGI process' failure and is explicitly marked as a candidate for retry.

Source

Thrown at pkg/app/master/probe/http/internal/fastcgi.go:91

	env, err := t.buildEnv(r)
	if err != nil {
		return nil, fmt.Errorf("building environment: %v", err)
	}

	network, address := "tcp", r.URL.Host

	if log.IsLevelEnabled(log.DebugLevel) {
		envJSON, _ := json.Marshal(env)
		log.Debugf("HTTP probe - FastCGI env - %s", string(envJSON))
	}

	ctx := r.Context()
	dialer := net.Dialer{Timeout: t.DialTimeout}
	fcgiBackend, err := DialWithDialerContext(ctx, network, address, dialer)
	if err != nil {
		// TODO: wrap in a special error type if the dial failed, so retries can happen if enabled
		return nil, fmt.Errorf("dialing backend: %v", err)
	}
	// fcgiBackend gets closed when response body is closed (see clientCloser)

	// read/write timeouts
	if err := fcgiBackend.SetReadTimeout(t.ReadTimeout); err != nil {
		return nil, fmt.Errorf("setting read timeout: %v", err)
	}
	if err := fcgiBackend.SetWriteTimeout(t.WriteTimeout); err != nil {
		return nil, fmt.Errorf("setting write timeout: %v", err)
	}

	contentLength := r.ContentLength
	if contentLength == 0 {
		contentLength, _ = strconv.ParseInt(r.Header.Get("Content-Length"), 10, 64)
	}

	var resp *http.Response
	switch r.Method {

View on GitHub (pinned to 81940d17fa)

Solutions

  1. Verify the backend address/port in the probe URL matches what the FastCGI server listens on (netstat/php-fpm config).
  2. If the backend uses a unix socket, configure the transport to dial unix instead of tcp.
  3. Increase DialTimeout and/or add retry logic — the code comments dial failures as retryable.
  4. Confirm the app process is running before probing (start ordering / readiness probes).

Example fix

// before: probing tcp while php-fpm listens on a socket
// after: point the transport at the socket
t := FastCGITransport{ /* network: "unix", address: "/run/php-fpm.sock", DialTimeout: 5 * time.Second */ }
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", host+":"+port, 3*time.Second)
if err != nil {
    return fmt.Errorf("FastCGI backend unreachable at %s:%s — start it first", host, port)
}
conn.Close()

Try / catch

var resp *http.Response
err := retry(3, backoff, func() error {
    var e error
    resp, e = fcgiTransport.RoundTrip(req)
    if e != nil && strings.Contains(e.Error(), "dialing backend") {
        return e // retryable per transport comments
    }
    return e
})

Prevention

When it happens

Trigger: RoundTrip when DialWithDialerContext fails: backend not listening on r.URL.Host's port, wrong network type (unix vs tcp), connection refused/timeout, or context cancellation before the dial completes.

Common situations: Probing a containerized PHP app whose php-fpm listens on a unix socket but the transport dials tcp; wrong port in the probe URL; app not yet started when the probe runs; firewall or NetworkPolicy blocking the connection.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of slimtoolkit/slim@81940d17fa (2026-08-31). Data as JSON: /api/errors/314d7422e4810c9f. Report an issue: GitHub.