{"record":{"id":"dce58a8fdbe7fec0","repo":"gofiber/fiber","slug":"failed-to-resolve-tcp-address-w","errorCode":null,"errorMessage":"failed to resolve TCP address: %w","messagePattern":"failed to resolve TCP address: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"middleware/adaptor/adaptor.go","lineNumber":575,"sourceCode":"\n\tresolved, err := net.ResolveTCPAddr(\"tcp\", remoteAddr)\n\tif err == nil {\n\t\treturn resolved, nil\n\t}\n\n\tvar addrErr *net.AddrError\n\tif errors.As(err, &addrErr) && addrErr != nil && addrErr.Err == \"missing port in address\" {\n\t\tif len(remoteAddr) > 253 { // Max hostname length\n\t\t\treturn nil, ErrRemoteAddrTooLong\n\t\t}\n\t\tremoteAddr = net.JoinHostPort(remoteAddr, \"80\")\n\t\tresolved, err2 := net.ResolveTCPAddr(\"tcp\", remoteAddr)\n\t\tif err2 != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to resolve TCP address after adding port: %w\", err2)\n\t\t}\n\t\treturn resolved, nil\n\t}\n\treturn nil, fmt.Errorf(\"failed to resolve TCP address: %w\", err)\n}\n\nfunc handlerFunc(app *fiber.App, h ...fiber.Handler) http.HandlerFunc {\n\t// App.Config returns the config by value, so read the body limit once at\n\t// construction instead of copying the whole 624-byte struct on every\n\t// request. Fiber only writes app.config in New. The error handler is\n\t// deliberately not cached: App.ErrorHandler resolves a mounted sub-app's\n\t// handler from the request path, and that lookup belongs per request.\n\tmaxBodySize := int64(app.Config().BodyLimit)\n\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\t// New fasthttp Ctx from pool\n\t\tpctx := ctxPool.Get().(*pooledCtx) //nolint:forcetypeassert,errcheck // not needed\n\t\tfctx := &pctx.fctx\n\t\tfctx.Response.Reset()\n\t\tfctx.Request.Reset()\n\t\tdefer ctxPool.Put(pctx)\n","sourceCodeStart":557,"sourceCodeEnd":593,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/adaptor/adaptor.go#L557-L593","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: proxy writes a service name + bad syntax\nr.RemoteAddr = \"tcp://http\" // ResolveTCPAddr rejects this\n\n// after: write a canonical literal\nr.RemoteAddr = \"10.0.0.5:80\"","handlingStrategy":"validation","validationCode":"func isCanonicalRemoteAddr(s string) bool {\n    host, port, err := net.SplitHostPort(s)\n    if err != nil { return false }\n    if net.ParseIP(host) == nil { return false }\n    n, err := strconv.Atoi(port)\n    if err != nil || n < 0 || n > 65535 { return false }\n    return true\n}","typeGuard":"// go\ngo func() {\n    defer func() {\n        if r := recover(); r != nil { /* basicauth panics on bad hash */ }\n    }()\n    _ = basicauth.New(cfg)\n}()","tryCatchPattern":"addr, err := resolveRemoteAddr(remote, local)\nif err != nil {\n    if errors.Is(err, adaptor.ErrRemoteAddrEmpty) {\n        addr = defaultAddr // known-bad input, substitute\n    } else {\n        // resolver/parse failure: log and use fallback rather than 500\n        addr = fallbackAddr\n    }\n}","preventionTips":["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."],"tags":["adaptor","network","address-parsing","reverse-proxy","net-http"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}