bytebase/bytebase · error
exceeded max retries for %s %s
Error message
exceeded max retries for %s %s
What it means
doGraphRequest retries at most 3 times, and only when a response signals 401 plus a successful token refresh (retry=true). If all 3 attempts still yield retry signals, the loop exits and this sentinel error is returned. It means the Graph access token keeps being rejected even after refreshing, so the call never completes.
Source
Thrown at backend/plugin/webhook/teams/app.go:425
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, false, errors.Errorf("request failed with status %d: %s", resp.StatusCode, string(respBody))
}
return respBody, false, nil
}()
if err != nil {
return nil, err
}
if retry {
continue
}
return b, nil
}
return nil, errors.Errorf("exceeded max retries for %s %s", method, apiURL)
}
// Bot Framework types for messaging.
type activity struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
Attachments []attachment `json:"attachments,omitempty"`
}
type attachment struct {
ContentType string `json:"contentType"`
Content any `json:"content"`
}
// AdaptiveCard represents a Microsoft Adaptive Card.
// Adaptive Card schema: https://adaptivecards.io/explorer/
// Adaptive Card designer: https://adaptivecards.io/designer/View on GitHub (pinned to 1870550677)
Solutions
- Check refreshGraphToken requests scope "https://graph.microsoft.com/.default" and the token is a Graph token, not an Azure RM or Bot token.
- Verify admin consent is granted for the app's Graph permissions — tokens without consent get 401/403 repeatedly.
- Check server clock synchronization (NTP); large skew causes JWT rejection.
- Inspect the JWT claims (decode the access token at jwt.ms) to confirm aud/roles match the called endpoint.
Example fix
// before
return nil, errors.Errorf("exceeded max retries for %s %s", method, apiURL)
// after: include last status for diagnosability
return nil, errors.Errorf("exceeded max retries for %s %s (last status: %d)", method, apiURL, lastStatus) Defensive patterns
Strategy: fallback
Validate before calling
// decode the access token and check claims before use parts := strings.Split(graphToken, ".") // verify aud == "https://graph.microsoft.com" and roles contain required Graph permissions
Try / catch
if err != nil {
if strings.Contains(err.Error(), "exceeded max retries") {
// token is persistently rejected: recheck scopes, consent, and clock sync
}
return err
} Prevention
- Use scope https://graph.microsoft.com/.default when fetching the Graph token
- Verify admin consent for all required Graph roles before going live
- Run NTP on the server to avoid JWT clock-skew rejection
- Log the decoded token claims when retries exhaust for faster diagnosis
When it happens
Trigger: Three consecutive 401 responses from Graph API on the same URL even after refreshGraphToken succeeds each time — e.g. the token audience/resource claim is wrong, the app lacks consent so Graph rejects the token, or clock skew invalidating tokens.
Common situations: App registration configured for the wrong scope/audience (e.g. missing https://graph.microsoft.com/.default), Conditional Access or tenant policies rejecting service principal tokens, server clock drift breaking JWT validation.
Related errors
- token request failed (status %d): %s
- failed to refresh graph token
- failed to refresh token
- failed to refresh bot token
- failed to get id by email
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/0878232a459b4f35.
Report an issue: GitHub.