Tencent/WeKnora · error

parse dingtalk credentials: %w

Error message

parse dingtalk credentials: %w

What it means

The DingTalk IM adapter factory parses channel.Credentials via im.ParseCredentials before building the adapter. This error wraps any failure from that parse — malformed JSON or a non-map credentials value — so the DingTalk-specific context is preserved.

Source

Thrown at internal/im/dingtalk/factory.go:16

package dingtalk

import (
	"context"
	"fmt"

	"github.com/Tencent/WeKnora/internal/im"
)

// NewFactory returns an im.AdapterFactory for DingTalk channels.
// Supports "webhook" and "websocket" (stream mode, default).
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 dingtalk credentials: %w", err)
		}

		clientID := im.GetString(creds, "client_id")
		clientSecret := im.GetString(creds, "client_secret")
		cardTemplateID := im.GetString(creds, "card_template_id")

		mode := im.ResolveMode(channel, "websocket")

		switch mode {
		case "webhook":
			adapter := NewWebhookAdapter(clientID, clientSecret, cardTemplateID)
			return adapter, nil, nil

		case "websocket":
			wsCtx, wsCancel := context.WithCancel(context.Background())
			go im.RunSupervised(wsCtx, im.SupervisorConfig{
				Name: fmt.Sprintf("DingTalk channel %s", channel.ID),
				Connect: func(ctx context.Context) (func(), error) {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Fix the wrapped im.ParseCredentials error — validate that channel.Credentials is a JSON object with the expected keys.
  2. Re-save the DingTalk channel credentials as valid JSON: {"client_id":..., "client_secret":..., optional "card_template_id"}.
  3. Validate the credentials JSON with a JSON parser/linter before persisting the channel.

Example fix

// before
"credentials": "{client_id: abc}" // invalid JSON string
// after
"credentials": {"client_id": "abc", "client_secret": "xyz"}
Defensive patterns

Strategy: validation

Validate before calling

var probe map[string]any
if err := json.Unmarshal(channel.Credentials, &probe); err != nil {
    return fmt.Errorf("dingtalk credentials must be a JSON object: %w", err)
}

Type guard

func isJSONObject(b []byte) bool {
    var m map[string]any
    return json.Unmarshal(b, &m) == nil
}

Try / catch

adapter, cancel, err := dingtalkFactory(ctx, channel, handler)
if err != nil {
    if strings.Contains(err.Error(), "parse dingtalk credentials") {
        return fmt.Errorf("re-save DingTalk channel credentials as valid JSON")
    }
    return err
}

Prevention

When it happens

Trigger: Creating a DingTalk channel adapter where channel.Credentials is invalid JSON, null, or a non-object value.

Common situations: IM channel saved with malformed credentials JSON in the database/config; credentials field left as a raw string instead of an object; manual edits to channel config breaking JSON syntax.

Related errors


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