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

  1. Check network connectivity and that the token endpoint host is resolvable (curl the claudeMaxTokenUrl from the same machine).
  2. Verify proxy env vars (HTTP_PROXY/HTTPS_PROXY) and corporate CA certificates (SSL_CERT_FILE) are correct.
  3. Retry the refresh with backoff; transient network errors are common for background token refresh.
  4. Configure a client with an explicit timeout instead of http.DefaultClient so failures are deterministic.
  5. 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

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


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/540dcb1354779efc. Report an issue: GitHub.