{"record":{"id":"cf99e766d9e2a755","repo":"bytebase/bytebase","slug":"failed-to-get-id-by-email-cf99e7","errorCode":null,"errorMessage":"failed to get id by email","messagePattern":"failed to get id by email","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/webhook/teams/teams.go","lineNumber":173,"sourceCode":"\tp := newProvider(teams.TenantId, teams.ClientId, teams.ClientSecret)\n\tctx := context.Background()\n\n\tsent := map[string]bool{}\n\n\tif err := common.Retry(ctx, func() error {\n\t\tvar errs error\n\n\t\tvar emails []string\n\t\tfor _, u := range webhookCtx.MentionEndUsers {\n\t\t\tif sent[u.Email] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\temails = append(emails, u.Email)\n\t\t}\n\n\t\tidByEmail, err := p.getIDByEmail(ctx, emails)\n\t\tif err != nil {\n\t\t\treturn errors.Wrapf(err, \"failed to get id by email\")\n\t\t}\n\n\t\tfor _, u := range webhookCtx.MentionEndUsers {\n\t\t\tif sent[u.Email] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tid, ok := idByEmail[u.Email]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr := p.sendMessage(ctx, id, getAdaptiveCard(webhookCtx))\n\t\t\tif err != nil {\n\t\t\t\tslog.Error(\"Teams failed to send message\",\n\t\t\t\t\tslog.String(\"email\", u.Email),\n\t\t\t\t\tlog.BBError(err))\n\t\t\t\terr = errors.Wrapf(err, \"failed to send message to %s\", u.Email)\n\t\t\t\tmultierr.AppendInto(&errs, err)","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/webhook/teams/teams.go#L155-L191","documentation":"The Microsoft Graph lookup that maps user emails to Teams user IDs failed inside postDirectMessage, wrapped as 'failed to get id by email'. p.getIDByEmail authenticates against Microsoft Graph (tenant/client id/secret from the Teams IM setting) and queries users by email; any Graph API, auth, or network failure here is surfaced under this message. When this fails, direct @-mentions cannot be delivered and Post falls back to the channel webhook.","triggerScenarios":"Receiver.Post with DirectMessage=true and MentionEndUsers set; getTeamsConfig returns a Teams setting, then common.Retry -> p.getIDByEmail(ctx, emails) errors — expired/invalid client secret, Graph API 401/403, network failure, or a user principal not found/ambiguous in the tenant.","commonSituations":"Client secret expired in Azure AD app registration; app lacks User.Read.All (or equivalent) application permission with admin consent; tenant ID or client ID typo'd in Bytebase IM settings; user left the tenant so email no longer resolves; transient Graph API outages (retry is already applied via common.Retry).","solutions":["Check the wrapped cause: if 401/invalid_client, rotate the client secret in Azure AD app registration and update Bytebase Teams settings.","Grant the app the required Graph application permissions (e.g. User.Read.All) and admin consent them.","Verify tenant ID, client ID, and client secret in the Teams IM setting are correct.","Confirm mentioned users' emails match their Azure AD sign-in addresses (UPNs).","If Graph is transiently failing, rely on the existing retry or re-trigger the event; the channel webhook fallback still delivers the notification."],"exampleFix":"// before (assuming permission exists)\nidByEmail, err := p.getIDByEmail(ctx, emails)\n// after (pre-validate creds and log cause)\nif err := p.pingGraphAuth(ctx); err != nil {\n  return errors.Wrapf(err, \"teams graph auth invalid: check tenantId/clientId/secret and admin consent\")\n}\nidByEmail, err := p.getIDByEmail(ctx, emails)\nif err != nil { return errors.Wrapf(err, \"failed to get id by email\") }","handlingStrategy":"fallback","validationCode":"// preflight the Teams IM setting before enabling direct messages\nif tenantID == \"\" || clientID == \"\" || clientSecret == \"\" { return errors.New(\"teams direct message requires tenantId, clientId and clientSecret\") }\n_, err := p.getIDByEmail(ctx, []string{testUserEmail}) // dry-run one lookup","typeGuard":null,"tryCatchPattern":"delivered := postDirectMessage(ctx) // returns false on any failure\nif !delivered {\n    log.Warn(\"teams direct message failed; channel webhook fallback used\")\n    // Post() already falls back to the channel webhook — monitor logs for root cause\n}","preventionTips":["Rotate the Azure AD client secret before expiry and update Bytebase settings","Grant and admin-consent User.Read.All on the app registration","Keep mention emails in sync with Azure AD UPNs","Rely on the built-in channel-webhook fallback and monitor the 'failed to send direct message' warnings"],"tags":["microsoft-graph","authentication","teams","direct-message"],"backgroundTag":"upstream-api-error","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}