{"record":{"id":"e34ca61c7f5926a7","repo":"sipeed/picoclaw","slug":"wecom-bot-id-and-secret-are-required","errorCode":null,"errorMessage":"wecom bot_id and secret are required","messagePattern":"wecom bot_id and secret are required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/channels/wecom/wecom.go","lineNumber":113,"sourceCode":"\t\treturn true\n\t}\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\tif _, ok := s.seen[id]; ok {\n\t\treturn false\n\t}\n\tif old := s.ring[s.idx]; old != \"\" {\n\t\tdelete(s.seen, old)\n\t}\n\ts.ring[s.idx] = id\n\ts.idx = (s.idx + 1) % len(s.ring)\n\ts.seen[id] = struct{}{}\n\treturn true\n}\n\nfunc NewChannel(bc *config.Channel, cfg *config.WeComSettings, messageBus *bus.MessageBus) (*WeComChannel, error) {\n\tif cfg.BotID == \"\" || cfg.Secret.String() == \"\" {\n\t\treturn nil, fmt.Errorf(\"wecom bot_id and secret are required\")\n\t}\n\tif cfg.WebSocketURL == \"\" {\n\t\tcfg.WebSocketURL = wecomDefaultWebSocketURL\n\t}\n\n\tbase := channels.NewBaseChannel(\n\t\t\"wecom\",\n\t\tcfg,\n\t\tmessageBus,\n\t\tbc.AllowFrom,\n\t\tchannels.WithReasoningChannelID(bc.ReasoningChannelID),\n\t)\n\n\tch := &WeComChannel{\n\t\tBaseChannel: base,\n\t\tconfig:      cfg,\n\t\tpending:     make(map[string]chan wecomEnvelope),\n\t\tturns:       make(map[string][]wecomTurn),","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/wecom/wecom.go#L95-L131","documentation":"WeComChannel construction fails fast when either BotID or Secret is empty in the WeCom settings. These are the minimum credentials the channel needs to authenticate with the WeCom gateway, so NewChannel refuses to build rather than starting a channel that would fail every command. This is a configuration error at startup, not a runtime send failure.","triggerScenarios":"Instantiating the WeCom channel (via the channel manager during app bootstrap) with a config where channels.wecom.bot_id or channels.wecom.secret is missing or an empty string; Secret is a masked type, so it must have been set and .String() must return a non-empty value.","commonSituations":"Deploying with an incomplete YAML/JSON config (secret omitted in prod but present in dev); env-var interpolation producing an empty string (e.g. WECOM_SECRET not exported); renaming config keys in a template so the values never bind; copying an example config without filling in credentials.","solutions":["Set both bot_id and secret in the channels.wecom settings block of the config file","If values come from environment variables, verify they are actually exported and non-empty in the deployment environment (print the resolved config with the secret masked)","Check for typos/renamed keys in the config against the WeComSettings struct definition","Restart the service after fixing the config; the error occurs only at channel construction"],"exampleFix":"# before (config.yaml)\nchannels:\n  wecom:\n    bot_id: \"\"\n    # secret missing entirely\n\n# after\nchannels:\n  wecom:\n    bot_id: \"wecom-bot-123\"\n    secret: \"${WECOM_SECRET}\"  # exported and non-empty","handlingStrategy":"validation","validationCode":"func validateWeComConfig(cfg *config.WeComSettings) error {\n    if cfg.BotID == \"\" {\n        return errors.New(\"channels.wecom.bot_id is required\")\n    }\n    if cfg.Secret.String() == \"\" {\n        return errors.New(\"channels.wecom.secret is required\")\n    }\n    return nil\n}\n\n// run before constructing the channel / starting the app\nif err := validateWeComConfig(cfg); err != nil {\n    return err\n}","typeGuard":"func isWeComMissingCredentials(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"bot_id and secret are required\")\n}","tryCatchPattern":"ch, err := wecom.NewChannel(bc, cfg, bus)\nif err != nil {\n    if isWeComMissingCredentials(err) {\n        // fail startup loudly; do not run a degraded channel\n        log.Fatalf(\"config error: %v\", err)\n    }\n    return err\n}","preventionTips":["Fail fast at config load with a clear message instead of at channel construction","Use env-var interpolation with a startup assertion that resolved values are non-empty","Mask-check secrets in CI config validation (name-only, never print the value)"],"tags":["wecom","config","startup","credentials"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}