bytebase/bytebase · error
failed to get id by phone, errcode: %d, errmsg: %s
Error message
failed to get id by phone, errcode: %d, errmsg: %s
What it means
DingTalk returned a valid JSON response but with a non-zero errcode (other than 60121, which is treated as "user not found"); getIDByPhone converts it into errors.Errorf("failed to get id by phone, errcode: %d, errmsg: %s"). This is an application-level API rejection from DingTalk, not a transport error.
Source
Thrown at backend/plugin/webhook/dingtalk/app.go:97
if err != nil {
return "", errors.Wrapf(err, "failed to get id by phone")
}
var response struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
Result struct {
UserID string `json:"userid"`
} `json:"result"`
}
if err := json.Unmarshal(b, &response); err != nil {
return "", errors.Wrapf(err, "failed to unmarshal response")
}
if response.Errcode == 60121 {
userIDCache.Add(phone, "")
return "", nil
}
if response.Errcode != 0 {
return "", errors.Errorf("failed to get id by phone, errcode: %d, errmsg: %s", response.Errcode, response.Errmsg)
}
userIDCache.Add(phone, response.Result.UserID)
return response.Result.UserID, nil
}
// https://open.dingtalk.com/document/orgapp/chatbots-send-one-on-one-chat-messages-in-batches
func (p *provider) sendMessage(ctx context.Context, userIDs []string, title, text string) error {
const url = "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend"
markdown, err := json.Marshal(struct {
Title string `json:"title"`
Text string `json:"text"`
}{
Title: title,
Text: text,
})
if err != nil {
return errors.Wrapf(err, "failed to marshal markdown")View on GitHub (pinned to 1870550677)
Solutions
- Read the errcode/errmsg in the message and look it up in DingTalk's error code table
- Grant the app contact/user read permissions in the DingTalk developer console if errcode is permission-related
- Add the server's egress IP to the DingTalk app's IP whitelist (errcode 60020)
- Fix appKey/appSecret if errcode indicates invalid credentials
Example fix
// before // app without contact read scope // after // DingTalk admin console -> app -> Permissions: enable "Address book read" (通讯录只读)
Defensive patterns
Strategy: fallback
Validate before calling
// DingTalk errcode surfaces only after the call; pre-validate what you can:
if appIPWhitelist != nil && !appIPWhitelist.Contains(serverEgressIP) {
return errors.New("server egress IP not in DingTalk app IP whitelist (errcode 60020)")
} Try / catch
id, err := p.getIDByPhone(ctx, phone)
if err != nil {
var apiErr struct{ msg string }
log.Printf("dingtalk getbymobile rejected: %v", err) // includes errcode/errmsg
return "", nil // degrade: send webhook without this mention
} Prevention
- Grant the DingTalk app contact-read scope in the developer console before enabling mention lookups
- Keep the server's egress IPs listed in the app's IP whitelist
- Map common errcodes (60011, 60020, 60121, 88) to actionable messages for operators
When it happens
Trigger: The getbymobile API responds with errcode != 0 and != 60121, e.g. errcode 60011 (no permission), 60020 (IP not in whitelist), 88 (invalid app key/secret), or other org/permission errors.
Common situations: The mobile number is not a member of the authorized org; the app lacks contact-read permission; server IP is not whitelisted for the DingTalk app; invalid or expired app credentials.
Related errors
- failed to get user id by phone
- failed to get id by email, code %d, msg %s
- failed to send message, code %d, msg %q
- failed to open conversation, error: %v
- failed to post message, error: %v
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/cfe796cb0bc9e6e0.
Report an issue: GitHub.