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

  1. Run the Claude Max OAuth connect flow (connectClaudeMaxOauth) to obtain and store initial credentials.
  2. Verify the credentials file/config actually contains a claudeMax section.
  3. Check you are operating under the same account whose credentials were stored.
  4. 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

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


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