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

  1. Read the errcode/errmsg in the message and look it up in DingTalk's error code table
  2. Grant the app contact/user read permissions in the DingTalk developer console if errcode is permission-related
  3. Add the server's egress IP to the DingTalk app's IP whitelist (errcode 60020)
  4. 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

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


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/cfe796cb0bc9e6e0. Report an issue: GitHub.