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
- Log Request.RemoteAddr verbatim to see what the adaptor received.
- Ensure RemoteAddr is always ip:port; if a proxy sends X-Forwarded-For, parse it into a literal IP before assigning.
- For IPv6 with zones, strip the zone or use the fast-path-friendly [v6]:port form.
- Install or populate /etc/services if relying on service-name ports.
- 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
- Synthesize RemoteAddr only from validated ip:port inputs.
- Do not pass hostnames or service names through to the adaptor.
- Log the raw RemoteAddr when errors spike to spot upstream misbehavior.
- Strip zone IDs from IPv6 literals before assigning.
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
- failed to resolve TCP address after adding port
- remote address cannot be empty
- cache: failed to delete key
- cache: failed to get key
- cache: failed to get raw key
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)