gofiber/fiber · warning

failed to resolve TCP address

Error message

failed to resolve TCP address: %w

What it means

Returned by resolveRemoteAddr when net.ResolveTCPAddr fails on the original remoteAddr string and the failure is NOT 'missing port in address'. This is the catch-all for malformed or unresolvable remote addresses passed to the Fiber adaptor: invalid syntax, unknown port service name, unsupported network, or a resolver error other than a missing port.

Solutions

  1. Log Request.RemoteAddr verbatim to see what the adaptor received.
  2. Ensure RemoteAddr is always ip:port; if a proxy sends X-Forwarded-For, parse it into a literal IP before assigning.
  3. For IPv6 with zones, strip the zone or use the fast-path-friendly [v6]:port form.
  4. Install or populate /etc/services if relying on service-name ports.
  5. If you control the upstream, have it write a canonical ip:port string.

Example fix

// before: proxy writes a service name + bad syntax
r.RemoteAddr = "tcp://http" // ResolveTCPAddr rejects this

// after: write a canonical literal
r.RemoteAddr = "10.0.0.5:80"
Defensive patterns

Strategy: validation

Validate before calling

func isCanonicalRemoteAddr(s string) bool {
    host, port, err := net.SplitHostPort(s)
    if err != nil { return false }
    if net.ParseIP(host) == nil { return false }
    n, err := strconv.Atoi(port)
    if err != nil || n < 0 || n > 65535 { return false }
    return true
}

Type guard

// go
go func() {
    defer func() {
        if r := recover(); r != nil { /* basicauth panics on bad hash */ }
    }()
    _ = basicauth.New(cfg)
}()

Try / catch

addr, err := resolveRemoteAddr(remote, local)
if err != nil {
    if errors.Is(err, adaptor.ErrRemoteAddrEmpty) {
        addr = defaultAddr // known-bad input, substitute
    } else {
        // resolver/parse failure: log and use fallback rather than 500
        addr = fallbackAddr
    }
}

Prevention

When it happens

Trigger: RemoteAddr is empty (caught earlier by ErrRemoteAddrEmpty in practice), contains a service name not in /etc/services, has an invalid IPv6 literal, mixes network families, or carries a zone identifier the resolver rejects. The fast-path ip:port parser already declined, and the resolver confirms the address is unusable.

Common situations: A net/http handler upstream mutates Request.RemoteAddr to something other than ip:port; a load balancer injects a non-literal address; IPv6 with a zone id (%eth0) that net.ResolveTCPAddr on this platform dislikes; service-name ports ('http') on a minimal container without /etc/services.

Related errors


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

Appendix: source

Thrown at middleware/adaptor/adaptor.go:575

	resolved, err := net.ResolveTCPAddr("tcp", remoteAddr)
	if err == nil {
		return resolved, nil
	}

	var addrErr *net.AddrError
	if errors.As(err, &addrErr) && addrErr != nil && addrErr.Err == "missing port in address" {
		if len(remoteAddr) > 253 { // Max hostname length
			return nil, ErrRemoteAddrTooLong
		}
		remoteAddr = net.JoinHostPort(remoteAddr, "80")
		resolved, err2 := net.ResolveTCPAddr("tcp", remoteAddr)
		if err2 != nil {
			return nil, fmt.Errorf("failed to resolve TCP address after adding port: %w", err2)
		}
		return resolved, nil
	}
	return nil, fmt.Errorf("failed to resolve TCP address: %w", err)
}

func handlerFunc(app *fiber.App, h ...fiber.Handler) http.HandlerFunc {
	// App.Config returns the config by value, so read the body limit once at
	// construction instead of copying the whole 624-byte struct on every
	// request. Fiber only writes app.config in New. The error handler is
	// deliberately not cached: App.ErrorHandler resolves a mounted sub-app's
	// handler from the request path, and that lookup belongs per request.
	maxBodySize := int64(app.Config().BodyLimit)

	return func(w http.ResponseWriter, r *http.Request) {
		// New fasthttp Ctx from pool
		pctx := ctxPool.Get().(*pooledCtx) //nolint:forcetypeassert,errcheck // not needed
		fctx := &pctx.fctx
		fctx.Response.Reset()
		fctx.Request.Reset()
		defer ctxPool.Put(pctx)

View on GitHub (pinned to a105acad6c)