{"record":{"id":"0fca68248312e6df","repo":"charmbracelet/crush","slug":"failed-to-make-request-w","errorCode":null,"errorMessage":"failed to make request: %w","messagePattern":"failed to make request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/hyper/provider.go","lineNumber":94,"sourceCode":"\t\tbalance := int(lastKnownBalance.Load())\n\t\treturn &balance, nil\n\t}\n\n\treq, err := http.NewRequestWithContext(\n\t\tctx,\n\t\thttp.MethodGet,\n\t\tBaseURL()+\"/v1/credits\",\n\t\tnil,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not create request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\n\n\tclient := &http.Client{Timeout: 10 * time.Second}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to make request: %w\", err)\n\t}\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode)\n\t}\n\n\t// Teams with hypercredit display disabled get a balance_usd field\n\t// instead of balance, and no balance is shown for them at all.\n\tvar result struct {\n\t\tBalance *int `json:\"balance\"`\n\t}\n\tif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode response: %w\", err)\n\t}\n\n\treturn result.Balance, nil\n}","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/hyper/provider.go#L76-L112","documentation":"FetchCredits wraps errors from http.Client.Do when executing the GET <BaseURL>/v1/credits request. This covers DNS failures, connection refused/reset, TLS errors, and the client's 10-second timeout. The HTTP call never completed, so no status code exists.","triggerScenarios":"Network is down or DNS cannot resolve hyper.charm.land (or the HYPER_URL host); the server is unreachable/firewalled; TLS handshake fails (bad proxy, clock skew); the 10s client Timeout elapses; or ctx is canceled mid-request.","commonSituations":"Corporate proxy/VPN blocks hyper.charm.land; offline development; self-hosted HYPER_URL proxy not running (connection refused); slow networks tripping the 10-second timeout.","solutions":["Check basic reachability: `curl -v $HYPER_URL/v1/credits` (or https://hyper.charm.land/v1/credits) to see the underlying network error.","If self-hosting via HYPER_URL, verify the proxy is up and listening on the expected port.","Check proxy environment (HTTP_PROXY/HTTPS_PROXY) and VPN/firewall rules that may block the host.","For timeouts, retry the call; FetchCredits has no built-in retry and the client timeout is fixed at 10 seconds.","Respect ctx cancellation: if the caller canceled, fix the caller's timeout/deadline instead of retrying."],"exampleFix":"// before\nbalance, err := hyper.FetchCredits(ctx, apiKey)\nif err != nil { return err } // fails on transient network blips\n// after\nvar balance *int\nvar err error\nfor attempt := 0; attempt < 3; attempt++ {\n    balance, err = hyper.FetchCredits(ctx, apiKey)\n    if err == nil || ctx.Err() != nil || !errors.Is(err, context.DeadlineExceeded) && !isNetError(err) {\n        break\n    }\n    time.Sleep(time.Duration(attempt+1) * 500 * time.Second / 1000)\n}","handlingStrategy":"retry","validationCode":"conn, err := net.DialTimeout(\"tcp\", host(hyper.BaseURL())+\":443\", 3*time.Second)\nif err != nil {\n    return fmt.Errorf(\"hyper endpoint unreachable: %w\", err)\n}\nconn.Close()","typeGuard":"func isNetworkError(err error) bool {\n    var ne net.Error\n    if errors.As(err, &ne) { return true }\n    var oe *net.OpError\n    return errors.As(err, &oe) || errors.Is(err, context.DeadlineExceeded) || errors.Is(err, syscall.ECONNREFUSED)\n}","tryCatchPattern":"var balance *int\nerr := retryDo(3, 500*time.Millisecond, func() error {\n    var e error\n    balance, e = hyper.FetchCredits(ctx, apiKey)\n    if e != nil && isNetworkError(e) {\n        return e // retryable\n    }\n    return stop(e) // fatal\n})","preventionTips":["Wrap FetchCredits in bounded exponential-backoff retry for transient net/timeout errors only.","Monitor reachability of hyper.charm.land (or your HYPER_URL host) in health checks.","Document that the internal client timeout is fixed at 10s; keep caller deadlines comfortably above it.","Verify VPN/proxy rules allow the host in corporate environments."],"tags":["network","http-client","timeout","go"],"backgroundTag":"http-request-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}