Tencent/WeKnora · error
parse wechat credentials: %w
Error message
parse wechat credentials: %w
What it means
The WeChat factory parses the channel's Credentials JSON blob with im.ParseCredentials before extracting bot_token and ilink_bot_id. This error wraps any failure of that parse — the credentials field is missing, empty, or not valid JSON. The wrapped inner error carries the exact JSON failure reason.
Source
Thrown at internal/im/wechat/factory.go:17
package wechat
import (
"context"
"fmt"
"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)
}
}()View on GitHub (pinned to 988cbb0330)
Solutions
- Validate channel.Credentials with json.Valid / im.ParseCredentials before creating the adapter and fix the JSON.
- Set credentials to a JSON object containing at least bot_token and ilink_bot_id, e.g. {"bot_token":"...","ilink_bot_id":"..."}.
- Log the inner wrapped error (fmt.Errorf %w chain) to identify the exact JSON syntax problem.
Example fix
// before
ch.Credentials = "bot_token=abc; ilink_bot_id=xyz"
// after
ch.Credentials = `{"bot_token":"abc","ilink_bot_id":"xyz"}` Defensive patterns
Strategy: validation
Validate before calling
if !json.Valid([]byte(ch.Credentials)) {
return fmt.Errorf("wechat channel %d: credentials is not valid JSON", ch.ID)
}
if _, err := im.ParseCredentials(ch.Credentials); err != nil {
return fmt.Errorf("wechat channel %d credentials: %w", ch.ID, err)
} Type guard
func hasValidWeChatCreds(raw string) bool {
creds, err := im.ParseCredentials(raw)
return err == nil && creds != nil
} Try / catch
adapter, cancel, err := wechatFactory(ctx, ch, handler)
if err != nil {
if strings.Contains(err.Error(), "parse wechat credentials") {
return fmt.Errorf("channel %d: credentials JSON invalid — %w", ch.ID, err)
}
return err
} Prevention
- Store credentials as marshalled JSON objects, never free-form text.
- Run json.Valid on the credentials field in the channel-create handler.
- Use a typed config struct marshalled to JSON to eliminate hand-written JSON errors.
When it happens
Trigger: Creating a WeChat adapter (factory invocation with an IMChannel) whose channel.Credentials is empty, malformed JSON (e.g. trailing commas, single quotes), or a non-JSON value.
Common situations: Channel created without filling in the credentials JSON; manual DB edits writing invalid JSON; secrets stored as YAML or INI text pasted into the credentials field.
Related errors
- wechat credentials require bot_token and ilink_bot_id
- E2BAPIKey is required for the E2B backend
- failed to generate KS3 presigned URL: %w
- S3 access key and secret key must be provided together
- failed to load AWS config: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/e32f95003ff68a6e.
Report an issue: GitHub.