plandex-ai/plandex · error
refresh failed - http: %w
Error message
refresh failed - http: %w
What it means
refreshCreds wraps the error from http.DefaultClient.Do when the POST to the Claude Max OAuth token endpoint fails at the transport level. This means no HTTP response was received: DNS failure, refused connection, TLS error, timeout, or proxy problem.
Source
Thrown at app/cli/lib/claude_max.go:309
body, err := json.Marshal(map[string]any{
"grant_type": "refresh_token",
"refresh_token": creds.RefreshToken,
"client_id": claudeMaxClientId,
})
if err != nil {
return nil, 0, fmt.Errorf("refresh failed - marshal: %w", err)
}
req, err := http.NewRequest("POST", claudeMaxTokenUrl, bytes.NewReader(body))
if err != nil {
return nil, 0, fmt.Errorf("refresh failed - create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("anthropic-beta", shared.AnthropicClaudeMaxBetaHeader)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, 0, fmt.Errorf("refresh failed - http: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
b, err := io.ReadAll(resp.Body)
if err != nil {
return nil, 0, fmt.Errorf("refresh failed - read body: %w", err)
}
return nil, resp.StatusCode, fmt.Errorf("refresh failed - status %d: %s", resp.StatusCode, b)
}
var r types.OauthResponse
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
return nil, 0, fmt.Errorf("refresh failed - decode: %w", err)
}
newCreds := &types.OauthCreds{
OauthResponse: r,View on GitHub (pinned to e2d772072e)
Solutions
- Check network connectivity and that the token endpoint host is resolvable (curl the claudeMaxTokenUrl from the same machine).
- Verify proxy env vars (HTTP_PROXY/HTTPS_PROXY) and corporate CA certificates (SSL_CERT_FILE) are correct.
- Retry the refresh with backoff; transient network errors are common for background token refresh.
- Configure a client with an explicit timeout instead of http.DefaultClient so failures are deterministic.
- If using a custom endpoint, confirm it is reachable and not blocked by firewall rules.
Example fix
// before
client := http.DefaultClient
// after
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, 0, fmt.Errorf("refresh failed - http: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// quick reachability probe before refresh
conn, err := net.DialTimeout("tcp", host+":443", 5*time.Second)
if err != nil {
return fmt.Errorf("token endpoint unreachable: %w", err)
}
conn.Close() Try / catch
var netErr net.Error
resp, err := client.Do(req)
if err != nil {
if errors.As(err, &netErr) && netErr.Timeout() {
return retryWithBackoff(refreshCreds, 3) // transient
}
return fmt.Errorf("refresh failed - http: %w", err)
} Prevention
- Use an http.Client with an explicit Timeout instead of http.DefaultClient.
- Add exponential backoff with jitter for transient network failures.
- Monitor proxy env vars and corporate CA trust in the deployment environment.
- Cache valid credentials and refresh proactively before expiry to reduce request pressure.
When it happens
Trigger: http.DefaultClient.Do(req) returns err while refreshing OAuth credentials — network unreachable, DNS resolution failure for the token host, TLS handshake failure, or the default HTTP client's timeout (or context deadline) expiring.
Common situations: Offline or restricted network, corporate proxy/firewall blocking the token endpoint, DNS misconfiguration, expired local CA certs causing TLS errors, or http.DefaultClient's zero-value timeout plus a hanging connection.
Related errors
- token exchange failed - error reading body: %s
- connection to plan stream timed out due to missing heartbeat
- token exchange failed - error creating request: %s
- token exchange failed - status: %d, body: %s
- refresh failed - create request: %w
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/540dcb1354779efc.
Report an issue: GitHub.