{"record":{"id":"0878232a459b4f35","repo":"bytebase/bytebase","slug":"exceeded-max-retries-for-s-s","errorCode":null,"errorMessage":"exceeded max retries for %s %s","messagePattern":"exceeded max retries for (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/webhook/teams/app.go","lineNumber":425,"sourceCode":"\t\t\t}\n\n\t\t\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\t\t\treturn nil, false, errors.Errorf(\"request failed with status %d: %s\", resp.StatusCode, string(respBody))\n\t\t\t}\n\n\t\t\treturn respBody, false, nil\n\t\t}()\n\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif retry {\n\t\t\tcontinue\n\t\t}\n\t\treturn b, nil\n\t}\n\n\treturn nil, errors.Errorf(\"exceeded max retries for %s %s\", method, apiURL)\n}\n\n// Bot Framework types for messaging.\n\ntype activity struct {\n\tType        string       `json:\"type\"`\n\tText        string       `json:\"text,omitempty\"`\n\tAttachments []attachment `json:\"attachments,omitempty\"`\n}\n\ntype attachment struct {\n\tContentType string `json:\"contentType\"`\n\tContent     any    `json:\"content\"`\n}\n\n// AdaptiveCard represents a Microsoft Adaptive Card.\n// Adaptive Card schema: https://adaptivecards.io/explorer/\n// Adaptive Card designer: https://adaptivecards.io/designer/","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/webhook/teams/app.go#L407-L443","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nreturn nil, errors.Errorf(\"exceeded max retries for %s %s\", method, apiURL)\n// after: include last status for diagnosability\nreturn nil, errors.Errorf(\"exceeded max retries for %s %s (last status: %d)\", method, apiURL, lastStatus)","handlingStrategy":"fallback","validationCode":"// decode the access token and check claims before use\nparts := strings.Split(graphToken, \".\")\n// verify aud == \"https://graph.microsoft.com\" and roles contain required Graph permissions","typeGuard":null,"tryCatchPattern":"if err != nil {\n\tif strings.Contains(err.Error(), \"exceeded max retries\") {\n\t\t// token is persistently rejected: recheck scopes, consent, and clock sync\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["authentication","retry","oauth","microsoft-graph"],"backgroundTag":"jwt-token-expired","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}