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

  1. Validate channel.Credentials with json.Valid / im.ParseCredentials before creating the adapter and fix the JSON.
  2. Set credentials to a JSON object containing at least bot_token and ilink_bot_id, e.g. {"bot_token":"...","ilink_bot_id":"..."}.
  3. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/e32f95003ff68a6e. Report an issue: GitHub.