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

  1. Inspect the claudeMaxTokenUrl constant and any config/env value feeding it; verify it is a valid absolute URL (e.g. https://...).
  2. Log the exact URL string in the error path to see what is being parsed.
  3. Add a startup validation (url.Parse) that fails fast if the token URL is empty or unparsable.
  4. 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

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


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