{"record":{"id":"784e36547583692e","repo":"charmbracelet/crush","slug":"failed-to-make-request-w-784e36","errorCode":null,"errorMessage":"failed to make request: %w","messagePattern":"failed to make request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/hyper.go","lineNumber":161,"sourceCode":"\tvar result catwalk.Provider\n\treq, err := http.NewRequestWithContext(\n\t\tctx,\n\t\thttp.MethodGet,\n\t\tr.baseURL+\"/api/v1/provider\",\n\t\tnil,\n\t)\n\tif err != nil {\n\t\treturn result, fmt.Errorf(\"could not create request: %w\", err)\n\t}\n\txetag.Request(req, etag)\n\tif apiKey := r.resolveKey(); apiKey != \"\" {\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\n\t}\n\n\tclient := &http.Client{Timeout: 30 * time.Second}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn result, fmt.Errorf(\"failed to make request: %w\", err)\n\t}\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\tif resp.StatusCode == http.StatusNotModified {\n\t\treturn result, catwalk.ErrNotModified\n\t}\n\n\tif resp.StatusCode == http.StatusUnauthorized {\n\t\treturn result, errUnauthorized\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn result, fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode)\n\t}\n\n\tif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {\n\t\treturn result, fmt.Errorf(\"failed to decode response: %w\", err)\n\t}","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/hyper.go#L143-L179","documentation":"This error wraps a network/transport failure from the Hyper API HTTP client in doGet. It is returned when http.Client.Do fails before a response is received — DNS failure, connection refused, timeout (30s), TLS error, or context cancellation. Callers of Get see it via the wrapped error chain.","triggerScenarios":"Calling config.Get (which calls doGet) when the Hyper endpoint is unreachable, the network is down, DNS resolution fails, the request exceeds the 30-second client timeout, or TLS handshake fails.","commonSituations":"Working offline or behind a corporate proxy that blocks the endpoint; DNS misconfiguration; slow/misbehaving API causing 30s timeout; firewall dropping connections.","solutions":["Verify network connectivity and that the Hyper API host is reachable (curl the endpoint).","Check proxy environment variables (HTTP_PROXY/HTTPS_PROXY) and corporate proxy settings.","Check whether the request is timing out after 30s and address latency or increase tolerance.","Confirm DNS resolves the API host correctly (dig/nslookup)."],"exampleFix":"// before: no way to distinguish network failure\nresp, err := client.Do(req)\nif err != nil {\n\treturn result, fmt.Errorf(\"failed to make request: %w\", err)\n}\n// after: caller inspects the wrapped error\nvar netErr net.Error\nif errors.As(err, &netErr) && netErr.Timeout() {\n\t// retry with backoff\n}","handlingStrategy":"retry","validationCode":"if _, err := net.LookupTimeout(\"tcp\", \"api.hyper.example:443\", 3*time.Second); err != nil {\n\t// skip network-dependent init\n}","typeGuard":"var netErr net.Error\nisTimeout := errors.As(err, &netErr) && netErr.Timeout()","tryCatchPattern":"cfg, err := config.Get()\nif err != nil && strings.Contains(err.Error(), \"failed to make request\") {\n\tvar netErr net.Error\n\tif errors.As(err, &netErr) && netErr.Timeout() {\n\t\t// retry with backoff\n\t}\n}","preventionTips":["Check connectivity before network-dependent operations.","Respect proxy env vars in restricted environments.","Wrap network calls in bounded retry with backoff.","Cache last-known-good config for offline fallback."],"tags":["network","http-client","timeout"],"backgroundTag":"http-request-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}