{"record":{"id":"b4ff339858dd2e48","repo":"sipeed/picoclaw","slug":"dingtalk-client-id-and-client-secret-are-required","errorCode":null,"errorMessage":"dingtalk client_id and client_secret are required","messagePattern":"dingtalk client_id and client_secret are required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/dingtalk/dingtalk.go","lineNumber":45,"sourceCode":"\t*channels.BaseChannel\n\tconfig       *config.DingTalkSettings\n\tclientID     string\n\tclientSecret string\n\tstreamClient *client.StreamClient\n\tctx          context.Context\n\tcancel       context.CancelFunc\n\t// Map to store session webhooks for each chat\n\tsessionWebhooks sync.Map // chatID -> sessionWebhook\n}\n\n// NewDingTalkChannel creates a new DingTalk channel instance\nfunc NewDingTalkChannel(\n\tbc *config.Channel,\n\tcfg *config.DingTalkSettings,\n\tmessageBus *bus.MessageBus,\n) (*DingTalkChannel, error) {\n\tif cfg.ClientID == \"\" || cfg.ClientSecret.String() == \"\" {\n\t\treturn nil, fmt.Errorf(\"dingtalk client_id and client_secret are required\")\n\t}\n\n\t// Set the logger for the Stream SDK\n\tdinglog.SetLogger(logger.NewLogger(\"dingtalk\"))\n\n\tbase := channels.NewBaseChannel(\"dingtalk\", cfg, messageBus, bc.AllowFrom,\n\t\tchannels.WithMaxMessageLength(20000),\n\t\tchannels.WithGroupTrigger(bc.GroupTrigger),\n\t\tchannels.WithReasoningChannelID(bc.ReasoningChannelID),\n\t)\n\n\treturn &DingTalkChannel{\n\t\tBaseChannel:  base,\n\t\tconfig:       cfg,\n\t\tclientID:     cfg.ClientID,\n\t\tclientSecret: cfg.ClientSecret.String(),\n\t}, nil\n}","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/dingtalk/dingtalk.go#L27-L63","documentation":"NewDingTalkChannel fails fast when either ClientID or ClientSecret in DingTalkSettings is empty. It is a construction-time config validation fired before any SDK client is built, so the channel is never registered when credentials are missing.","triggerScenarios":"Constructing the dingtalk channel with a config block that omits client_id/client_secret, has empty strings, or references an env var for the secret that is unset at process start.","commonSituations":"First-time setup using a config template without filling values, typoed YAML keys, secret sourced from an env var missing in docker-compose/systemd units, deploying with a different environment than local dev.","solutions":["Set both dingtalk.client_id and dingtalk.client_secret in the config (create a robot on DingTalk Open Platform and copy its AppKey/AppSecret)","If the secret comes from an environment variable, verify it is set in the service environment (docker env, systemd EnvironmentFile) and restart","Check YAML indentation and exact key names against the config reference"],"exampleFix":"# before\nchannels:\n  dingtalk:\n    enabled: true\n\n# after\nchannels:\n  dingtalk:\n    enabled: true\n    client_id: \"ding0nxxxxxxx\"\n    client_secret: \"your-app-secret\"","handlingStrategy":"validation","validationCode":"func validateDingTalkConfig(cfg *config.DingTalkSettings) error {\n    if cfg.ClientID == \"\" || cfg.ClientSecret.String() == \"\" {\n        return fmt.Errorf(\"dingtalk client_id and client_secret are required\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate dingtalk credentials at config load time, before channel construction","If secrets come from env vars, add a startup check that they resolve non-empty","Use a config linter/schema validation so missing keys fail fast with clear messages"],"tags":["dingtalk","config","validation","credentials"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}