{"record":{"id":"f2cba512f5266fae","repo":"affaan-m/ECC","slug":"fetch-s-w","errorCode":null,"errorMessage":"fetch %s: %w","messagePattern":"fetch (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"skills/golang-patterns/SKILL.md","lineNumber":212,"sourceCode":"    close(results)\n}\n```\n\n### Context for Cancellation and Timeouts\n\n```go\nfunc FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {\n    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n    defer cancel()\n\n    req, err := http.NewRequestWithContext(ctx, \"GET\", url, nil)\n    if err != nil {\n        return nil, fmt.Errorf(\"create request: %w\", err)\n    }\n\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        return nil, fmt.Errorf(\"fetch %s: %w\", url, err)\n    }\n    defer resp.Body.Close()\n\n    return io.ReadAll(resp.Body)\n}\n```\n\n### Graceful Shutdown\n\n```go\nfunc GracefulShutdown(server *http.Server) {\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\n    <-quit\n    log.Println(\"Shutting down server...\")\n\n    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/golang-patterns/SKILL.md#L194-L230","documentation":"Wrapped error from FetchWithTimeout in golang-patterns, raised on the network round-trip. After the request is built, http.DefaultClient.Do(req) is called; any failure is wrapped as fmt.Errorf(\"fetch %s: %w\", url, err). This message means the HTTP client could not successfully complete the exchange with the server - DNS, connection, TLS, or the context deadline fired.","triggerScenarios":"Calling FetchWithTimeout(ctx, url) where http.DefaultClient.Do(req) returns a non-nil error. Concrete triggers: DNS resolution failure, TCP connection refused or timed out, TLS handshake error, the 5-second context deadline exceeded, a proxy error, or a mid-stream reset.","commonSituations":"Target host is wrong or unreachable from the runtime (network policy, firewall); the 5*time.Second timeout is too short for slow endpoints; TLS certificate is expired or untrusted; HTTP_PROXY/HTTPS_PROXY env vars point at an unreachable proxy; IPv6-only host reached from an IPv4-only network.","solutions":["Classify with errors.Is against url.Error and net.Error; retry only on Timeout() || Temporary().","Increase the context timeout (or make it configurable) for endpoints known to be slow.","Verify reachability with curl/wget and inspect DNS + TLS from the same environment.","Check HTTP_PROXY/HTTPS_PROXY/NO_PROXY if a proxy is in play.","Use a tuned *http.Client (custom Transport, DialContext, IdleConnTimeout) instead of DefaultClient for production callers."],"exampleFix":"// before\nresp, err := http.DefaultClient.Do(req)\nif err != nil {\n    return nil, fmt.Errorf(\"fetch %s: %w\", url, err)\n}\n\n// after - separate retriable network errors from final failures\nresp, err := http.DefaultClient.Do(req)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) && (netErr.Timeout() || netErr.Temporary()) {\n        return nil, retryable(fmt.Errorf(\"fetch %s: %w\", url, err))\n    }\n    return nil, fmt.Errorf(\"fetch %s: %w\", url, err)\n}","handlingStrategy":"retry","validationCode":"func reachable(ctx context.Context, urlStr string) error {\n    u, err := url.Parse(urlStr)\n    if err != nil || u.Host == \"\" {\n        return fmt.Errorf(\"no host to dial\")\n    }\n    // best-effort DNS preflight\n    _, err = net.DefaultResolver.LookupHost(ctx, u.Hostname())\n    return err\n}","typeGuard":"func isRetriableHTTPError(err error) bool {\n    var netErr net.Error\n    if errors.As(err, &netErr) && (netErr.Timeout() || netErr.Temporary()) {\n        return true\n    }\n    var ue *url.Error\n    return errors.As(err, &ue) // url.Error wraps transient op errors\n}","tryCatchPattern":"var body []byte\nerr := retryWithBackoff(func() error {\n    resp, err := client.Do(req)\n    if err != nil {\n        if isRetriableHTTPError(err) {\n            return err // retriable\n        }\n        return errwrap.Stop(err) // final\n    }\n    defer resp.Body.Close()\n    if resp.StatusCode >= 500 {\n        return fmt.Errorf(\"status %d\", resp.StatusCode)\n    }\n    body, err = io.ReadAll(resp.Body)\n    return err\n})","preventionTips":["Use a configured *http.Client with sensible Transport timeouts, not DefaultClient.","Set a context deadline appropriate to the endpoint's latency.","Retry only on Timeout()/Temporary() with bounded backoff.","Check proxy env (HTTP_PROXY/HTTPS_PROXY) when debugging."],"tags":["go","http","network","timeout","error-wrapping"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}