Tencent/WeKnora · error
wechat credentials require bot_token and ilink_bot_id
Error message
wechat credentials require bot_token and ilink_bot_id
What it means
After successfully parsing the WeChat channel's credentials JSON, the factory requires both the bot_token and ilink_bot_id keys to be present and non-empty. This error is returned when either key is missing or an empty string, indicating an incomplete credential configuration for the iLink bot.
Source
Thrown at internal/im/wechat/factory.go:24
"github.com/Tencent/WeKnora/internal/im"
"github.com/Tencent/WeKnora/internal/logger"
)
// NewFactory returns an im.AdapterFactory for WeChat channels (iLink bot).
// WeChat only supports a long-polling mode, so there is no mode branch.
func NewFactory() im.AdapterFactory {
return func(factoryCtx context.Context, channel *im.IMChannel, msgHandler func(context.Context, *im.IncomingMessage) error) (im.Adapter, context.CancelFunc, error) {
creds, err := im.ParseCredentials(channel.Credentials)
if err != nil {
return nil, nil, fmt.Errorf("parse wechat credentials: %w", err)
}
botToken := im.GetString(creds, "bot_token")
ilinkBotID := im.GetString(creds, "ilink_bot_id")
if botToken == "" || ilinkBotID == "" {
return nil, nil, fmt.Errorf("wechat credentials require bot_token and ilink_bot_id")
}
adapter := NewAdapter(botToken, ilinkBotID)
client := NewLongPollClient(botToken, ilinkBotID, msgHandler)
pollCtx, pollCancel := context.WithCancel(context.Background())
go func() {
if err := client.Start(pollCtx); err != nil && pollCtx.Err() == nil {
logger.Errorf(context.Background(), "[IM] WeChat long-poll stopped for channel %s: %v", channel.ID, err)
}
}()
return adapter, pollCancel, nil
}
}
View on GitHub (pinned to 988cbb0330)
Solutions
- Add both keys to the channel credentials JSON: {"bot_token":"<token>","ilink_bot_id":"<id>"}.
- Fetch the missing ilink_bot_id from the WeChat iLink bot settings and store it on the channel.
- Add a pre-save validation on IMChannel for WeChat channels checking both keys are non-empty.
Example fix
// before
ch.Credentials = `{"bot_token":"abc"}`
// after
ch.Credentials = `{"bot_token":"abc","ilink_bot_id":"ilink-123"}` Defensive patterns
Strategy: validation
Validate before calling
creds, err := im.ParseCredentials(ch.Credentials)
if err == nil {
if im.GetString(creds, "bot_token") == "" || im.GetString(creds, "ilink_bot_id") == "" {
return fmt.Errorf("wechat channel %d: credentials must include non-empty bot_token and ilink_bot_id", ch.ID)
}
} Type guard
func weChatCredsComplete(raw string) bool {
creds, err := im.ParseCredentials(raw)
if err != nil {
return false
}
return im.GetString(creds, "bot_token") != "" && im.GetString(creds, "ilink_bot_id") != ""
} Try / catch
adapter, cancel, err := wechatFactory(ctx, ch, handler)
if err != nil {
if strings.Contains(err.Error(), "bot_token and ilink_bot_id") {
return fmt.Errorf("channel %d missing iLink credentials — set bot_token and ilink_bot_id", ch.ID)
}
return err
} Prevention
- Collect both fields as required inputs in the channel setup UI.
- Use a secret template/checklist when provisioning iLink bots.
- Fail fast at channel-save time rather than at adapter creation.
When it happens
Trigger: Invoking the WeChat factory with a channel whose credentials JSON parses but lacks bot_token and/or ilink_bot_id, or has them set to "".
Common situations: Only the bot token was provisioned and the iLink bot ID was never copied from the WeChat admin console; placeholder values left empty in a config template; redacted credentials injected by a CI secret system that dropped one key.
Related errors
- parse wechat credentials: %w
- cannot verify OIDC id_token: issuer is not configured
- E2BAPIKey is required for the E2B backend
- failed to generate KS3 presigned URL: %w
- S3 access key and secret key must be provided together
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/53bf1b15f47e3586.
Report an issue: GitHub.