chenhg5/cc-connect · error

api code=

Error message

api code=%d

What it means

Thrown when the Feishu bot-info API responds successfully at the HTTP layer but the envelope-level business code is non-zero, meaning Feishu rejected the operation (auth, permission, or app issue). The numeric Feishu code is embedded in the message for diagnosis.

Solutions

  1. Look up the numeric code in Feishu's API error-code docs to identify the exact cause.
  2. Verify app_id/app_secret in config.toml and that the token fetch succeeds.
  3. Enable bot capability and the required scopes in the Feishu developer console, then republish the app.
  4. Re-fetch a fresh tenant_access_token if the code indicates token invalidity (e.g. 99991661/99991663).
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: verify credentials by fetching token before calling bot-info
_, err := fetchFreshTenantAccessToken(ctx)
if err != nil { /* abort early */ }

Type guard

func botInfoOK(result botInfoResult) bool { return result.Code == 0 && result.Bot.OpenID != "" }

Try / catch

botID, err := getBotOpenID(ctx)
if err != nil {
	if strings.Contains(err.Error(), "code=99991") { /* token problem: refresh */ }
	return err
}

Prevention

When it happens

Trigger: Calling the bot-info endpoint with an app whose tenant_access_token is invalid/expired, the app lacks bot capability enabled, or lacks permission to read bot info — Feishu returns code!=0 in the body.

Common situations: App not configured as a bot in the Feishu developer console, missing bot:info scope, wrong app_id/app_secret in config.toml, or app not published to the tenant.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/98ef6ae64e5a7d97. Report an issue: GitHub.

Appendix: source

Thrown at platform/feishu/feishu.go:3827

// fetchBotOpenID retrieves the bot's open_id via the Feishu bot info API.
func (p *Platform) fetchBotOpenID() (string, error) {
	resp, err := p.client.Get(context.Background(),
		"/open-apis/bot/v3/info", nil, larkcore.AccessTokenTypeTenant)
	if err != nil {
		return "", fmt.Errorf("api call: %w", err)
	}
	var result struct {
		Code int `json:"code"`
		Bot  struct {
			OpenID string `json:"open_id"`
		} `json:"bot"`
	}
	if err := json.Unmarshal(resp.RawBody, &result); err != nil {
		return "", fmt.Errorf("parse response: %w", err)
	}
	if result.Code != 0 {
		return "", fmt.Errorf("api code=%d", result.Code)
	}
	return result.Bot.OpenID, nil
}

func isBotMentioned(mentions []*larkim.MentionEvent, botOpenID string) bool {
	for _, m := range mentions {
		if m.Id != nil && m.Id.OpenId != nil && *m.Id.OpenId == botOpenID {
			return true
		}
	}
	return false
}

// filterQuotedFilesForUser applies the two gating rules for issue #1560
// without downloading anything yet:
//  1. The triggering message must explicitly @-mention the bot. We never
//     pull quoted files for messages that quote a file but do not address
//     the bot — avoids silent background work on every chatter message

View on GitHub (pinned to 4000b2338a)