plandex-ai/plandex · error
refresh failed - create request: %w
Error message
refresh failed - create request: %w
What it means
refreshCreds in claude_max.go wraps an error returned by http.NewRequest when building the OAuth token refresh POST to claudeMaxTokenUrl. http.NewRequest only fails on an invalid URL, an unsupported HTTP method, or a malformed body, so this indicates the token endpoint URL constant is structurally broken rather than a network problem.
Source
Thrown at app/cli/lib/claude_max.go:302
func refreshCreds(accountCreds *types.AccountCredentials) (*types.OauthCreds, int, error) {
creds := accountCreds.ClaudeMax
if creds == nil {
return nil, 0, fmt.Errorf("no stored Claude credentials")
}
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)
}
View on GitHub (pinned to e2d772072e)
Solutions
- Inspect the claudeMaxTokenUrl constant and any config/env value feeding it; verify it is a valid absolute URL (e.g. https://...).
- Log the exact URL string in the error path to see what is being parsed.
- Add a startup validation (url.Parse) that fails fast if the token URL is empty or unparsable.
- If the body is custom, confirm its Read method never returns an unsupported error type.
Example fix
// before
const claudeMaxTokenUrl = ""
// after
const claudeMaxTokenUrl = "https://api.anthropic.com/oauth/token" // valid absolute URL
// fail fast at startup
u, err := url.Parse(claudeMaxTokenUrl)
if err != nil || u.Scheme == "" || u.Host == "" {
panic("invalid claudeMaxTokenUrl")
} Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(claudeMaxTokenUrl)
if err != nil || u.Scheme == "" || u.Host == "" {
return fmt.Errorf("invalid token URL %q: %w", claudeMaxTokenUrl, err)
} Prevention
- Keep the token URL as a compile-time constant with a valid absolute URL.
- Validate the URL with url.Parse at startup, not at request time.
- Never construct the URL from unsanitized user/env input without validation.
When it happens
Trigger: http.NewRequest("POST", claudeMaxTokenUrl, bytes.NewReader(body)) returns a non-nil error — typically because claudeMaxTokenUrl fails url.Parse (malformed or empty URL), or the request body implements io.Reader incorrectly.
Common situations: A build-time misconfiguration or recent change of the claudeMaxTokenUrl constant (empty string, missing scheme, control characters), or a compiled-in default overwritten by a bad config/env value used to construct the URL.
Related errors
- token exchange failed - error creating request: %s
- token exchange failed - error reading body: %s
- token exchange failed - status: %d, body: %s
- refresh failed - http: %w
- refresh failed - status %d: %s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/cbf38ae57f5b9309.
Report an issue: GitHub.