plandex-ai/plandex · error
no stored Claude credentials
Error message
no stored Claude credentials
What it means
refreshCreds refreshes Claude Max OAuth tokens using the stored refresh token. Before doing anything it reads accountCreds.ClaudeMax; if no Claude Max credentials have ever been stored for the account, it returns this plain error because there is no refresh token to use.
Source
Thrown at app/cli/lib/claude_max.go:288
return "", err
}
return base64.RawURLEncoding.EncodeToString(buf), nil
}
func sha256Base64(verifier string) string {
sum := sha256.Sum256([]byte(verifier))
return base64.RawURLEncoding.EncodeToString(sum[:])
}
func needsRefresh(creds *types.OauthCreds) bool {
// refresh an hour early so we can make multiple calls before it expires
return time.Now().After(creds.ExpiresAt.Add(-1 * time.Hour))
}
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)
View on GitHub (pinned to e2d772072e)
Solutions
- Run the Claude Max OAuth connect flow (connectClaudeMaxOauth) to obtain and store initial credentials.
- Verify the credentials file/config actually contains a claudeMax section.
- Check you are operating under the same account whose credentials were stored.
- If credentials were lost, re-authenticate rather than retrying refresh.
Defensive patterns
Strategy: validation
Validate before calling
func hasClaudeMaxCreds(ac *types.AccountCredentials) bool {
return ac != nil && ac.ClaudeMax != nil && ac.ClaudeMax.RefreshToken != ""
}
// call before refresh-dependent work:
// if !hasClaudeMaxCreds(creds) { return connectClaudeMaxOauth() } Type guard
func claudeMaxCredsStored(ac *types.AccountCredentials) bool { return ac != nil && ac.ClaudeMax != nil } Try / catch
out, n, err := refreshCreds(accountCreds)
if err != nil {
if strings.Contains(err.Error(), "no stored Claude credentials") {
// fall back to interactive OAuth connect
return connectClaudeMaxOauth()
}
} Prevention
- Always run the OAuth connect flow before calling Max-specific APIs.
- Persist credentials atomically so partial writes never look like 'no credentials'.
- Guard refresh logic behind a stored-credentials check.
- Re-authenticate after config resets rather than retrying refresh.
When it happens
Trigger: refreshClaudeMaxCredsIfNeeded calls refreshCreds while accountCreds.ClaudeMax is nil — i.e. the user never completed the Claude Max OAuth connect flow, or the stored credentials blob was reset/cleared.
Common situations: Using Claude Max features before running the OAuth connect (connectClaudeMaxOauth); credentials file created by another provider flow only; credentials wiped by a config reset, reinstall, or account switch.
Related errors
- refresh failed - marshal: %w
- token exchange failed - error creating request: %s
- token exchange failed - error reading body: %s
- token exchange failed - status: %d, body: %s
- error getting account credentials: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/cd35e21036c747db.
Report an issue: GitHub.