{"record":{"id":"243ea0d1fbb55b8c","repo":"chenhg5/cc-connect","slug":"project-q-has-no-weixin-platform","errorCode":null,"errorMessage":"project %q has no weixin platform","messagePattern":"project %q has no weixin platform","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/config.go","lineNumber":2433,"sourceCode":"\t\tif cfg.Projects[i].Name == opts.ProjectName {\n\t\t\tprojectIdx = i\n\t\t\tbreak\n\t\t}\n\t}\n\tif projectIdx < 0 {\n\t\treturn nil, fmt.Errorf(\"project %q not found\", opts.ProjectName)\n\t}\n\n\tproj := &cfg.Projects[projectIdx]\n\tcandidates := make([]int, 0, len(proj.Platforms))\n\tfor i := range proj.Platforms {\n\t\tt := strings.ToLower(strings.TrimSpace(proj.Platforms[i].Type))\n\t\tif t == \"weixin\" {\n\t\t\tcandidates = append(candidates, i)\n\t\t}\n\t}\n\tif len(candidates) == 0 {\n\t\treturn nil, fmt.Errorf(\"project %q has no weixin platform\", opts.ProjectName)\n\t}\n\n\ttargetPos := 0\n\tif opts.PlatformIndex > 0 {\n\t\ttargetPos = opts.PlatformIndex - 1\n\t}\n\tif targetPos < 0 || targetPos >= len(candidates) {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"platform index %d out of range: project %q has %d weixin platform(s)\",\n\t\t\topts.PlatformIndex, opts.ProjectName, len(candidates),\n\t\t)\n\t}\n\n\tabsIdx := candidates[targetPos]\n\tplatform := &proj.Platforms[absIdx]\n\tif platform.Options == nil {\n\t\tplatform.Options = map[string]any{}\n\t}","sourceCodeStart":2415,"sourceCodeEnd":2451,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/config/config.go#L2415-L2451","documentation":"SaveWeixinPlatformCredentials requires the target project's config to contain at least one platform block whose type is \"weixin\" (case-insensitive, trimmed). It scans proj.Platforms collecting matching candidates; if none match, it refuses to proceed rather than silently creating one. This guards the raw-TOML span editor from writing credentials into a nonexistent weixin block.","triggerScenarios":"Calling SaveWeixinPlatformCredentials with opts.ProjectName naming a project whose platforms array contains no entry with type == \"weixin\" (e.g. only feishu/telegram), or a misspelled type value like \"wechat\" or \"weixin\" with stray characters.","commonSituations":"User set up a project with the wrong platform type, typo'd \"weixin\" in config.toml, or runs the WeChat credential setup flow (e.g. QR login) against a project configured for a different messaging platform.","solutions":["Add a platform block with type = \"weixin\" under the named project in config.toml","Fix the platform's type field if it's a typo (e.g. \"wechat\" -> \"weixin\")","Run the platform provisioning/setup command for weixin first so the block is created, then retry the credential update","Verify the project name in opts.ProjectName matches the intended project that actually has a weixin platform"],"exampleFix":"// before (config.toml)\n[[projects.platforms]]\ntype = \"wechat\"\n// after\n[[projects.platforms]]\ntype = \"weixin\"","handlingStrategy":"validation","validationCode":"func hasWeixinPlatform(cfg *config.Config, project string) bool {\n    for _, p := range cfg.Projects {\n        if p.Name != project { continue }\n        for _, pl := range p.Platforms {\n            if strings.ToLower(strings.TrimSpace(pl.Type)) == \"weixin\" { return true }\n        }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always declare a [[projects.platforms]] block with type = \"weixin\" before running WeChat credential setup","Grep config.toml for the platform type spelling; \"wechat\" will not match","Run platform provisioning before credential updates"],"tags":["config","toml","weixin","missing-platform"],"backgroundTag":"missing-required-config-field","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}