{"record":{"id":"53bf1b15f47e3586","repo":"Tencent/WeKnora","slug":"wechat-credentials-require-bot-token-and-ilink-bot","errorCode":null,"errorMessage":"wechat credentials require bot_token and ilink_bot_id","messagePattern":"wechat credentials require bot_token and ilink_bot_id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/wechat/factory.go","lineNumber":24,"sourceCode":"\n\t\"github.com/Tencent/WeKnora/internal/im\"\n\t\"github.com/Tencent/WeKnora/internal/logger\"\n)\n\n// NewFactory returns an im.AdapterFactory for WeChat channels (iLink bot).\n// WeChat only supports a long-polling mode, so there is no mode branch.\nfunc NewFactory() im.AdapterFactory {\n\treturn func(factoryCtx context.Context, channel *im.IMChannel, msgHandler func(context.Context, *im.IncomingMessage) error) (im.Adapter, context.CancelFunc, error) {\n\t\tcreds, err := im.ParseCredentials(channel.Credentials)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"parse wechat credentials: %w\", err)\n\t\t}\n\n\t\tbotToken := im.GetString(creds, \"bot_token\")\n\t\tilinkBotID := im.GetString(creds, \"ilink_bot_id\")\n\n\t\tif botToken == \"\" || ilinkBotID == \"\" {\n\t\t\treturn nil, nil, fmt.Errorf(\"wechat credentials require bot_token and ilink_bot_id\")\n\t\t}\n\n\t\tadapter := NewAdapter(botToken, ilinkBotID)\n\t\tclient := NewLongPollClient(botToken, ilinkBotID, msgHandler)\n\n\t\tpollCtx, pollCancel := context.WithCancel(context.Background())\n\t\tgo func() {\n\t\t\tif err := client.Start(pollCtx); err != nil && pollCtx.Err() == nil {\n\t\t\t\tlogger.Errorf(context.Background(), \"[IM] WeChat long-poll stopped for channel %s: %v\", channel.ID, err)\n\t\t\t}\n\t\t}()\n\n\t\treturn adapter, pollCancel, nil\n\t}\n}\n","sourceCodeStart":6,"sourceCodeEnd":40,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/wechat/factory.go#L6-L40","documentation":"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.","triggerScenarios":"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 \"\".","commonSituations":"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.","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."],"exampleFix":"// before\nch.Credentials = `{\"bot_token\":\"abc\"}`\n// after\nch.Credentials = `{\"bot_token\":\"abc\",\"ilink_bot_id\":\"ilink-123\"}`","handlingStrategy":"validation","validationCode":"creds, err := im.ParseCredentials(ch.Credentials)\nif err == nil {\n    if im.GetString(creds, \"bot_token\") == \"\" || im.GetString(creds, \"ilink_bot_id\") == \"\" {\n        return fmt.Errorf(\"wechat channel %d: credentials must include non-empty bot_token and ilink_bot_id\", ch.ID)\n    }\n}","typeGuard":"func weChatCredsComplete(raw string) bool {\n    creds, err := im.ParseCredentials(raw)\n    if err != nil {\n        return false\n    }\n    return im.GetString(creds, \"bot_token\") != \"\" && im.GetString(creds, \"ilink_bot_id\") != \"\"\n}","tryCatchPattern":"adapter, cancel, err := wechatFactory(ctx, ch, handler)\nif err != nil {\n    if strings.Contains(err.Error(), \"bot_token and ilink_bot_id\") {\n        return fmt.Errorf(\"channel %d missing iLink credentials — set bot_token and ilink_bot_id\", ch.ID)\n    }\n    return err\n}","preventionTips":["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."],"tags":["wechat","credentials","missing-config"],"backgroundTag":"missing-credential-field","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}