{"record":{"id":"e631fb95fc6286ef","repo":"chenhg5/cc-connect","slug":"config-s-needs-at-least-one-projects-platforms","errorCode":null,"errorMessage":"config: %s needs at least one [[projects.platforms]]","messagePattern":"config: (.+?) needs at least one \\[\\[projects\\.platforms\\]\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/config.go","lineNumber":1035,"sourceCode":"\t}\n\tswitch strings.ToLower(strings.TrimSpace(c.Relay.Visibility)) {\n\tcase \"\", \"full\", \"summary\", \"none\":\n\tdefault:\n\t\treturn fmt.Errorf(\"config: relay.visibility must be \\\"full\\\", \\\"summary\\\", or \\\"none\\\"\")\n\t}\n\tif len(c.Projects) == 0 {\n\t\treturn fmt.Errorf(\"config: at least one [[projects]] entry is required\")\n\t}\n\tfor i, proj := range c.Projects {\n\t\tprefix := fmt.Sprintf(\"projects[%d]\", i)\n\t\tif proj.Name == \"\" {\n\t\t\treturn fmt.Errorf(\"config: %s.name is required\", prefix)\n\t\t}\n\t\tif proj.Agent.Type == \"\" {\n\t\t\treturn fmt.Errorf(\"config: %s.agent.type is required\", prefix)\n\t\t}\n\t\tif len(proj.Platforms) == 0 && !permissive {\n\t\t\treturn fmt.Errorf(\"config: %s needs at least one [[projects.platforms]]\", prefix)\n\t\t}\n\t\tfor j, p := range proj.Platforms {\n\t\t\tif p.Type == \"\" {\n\t\t\t\treturn fmt.Errorf(\"config: %s.platforms[%d].type is required\", prefix, j)\n\t\t\t}\n\t\t}\n\t\tif proj.Mode == \"multi-workspace\" {\n\t\t\tif proj.BaseDir == \"\" {\n\t\t\t\treturn fmt.Errorf(\"project %q: multi-workspace mode requires base_dir\", proj.Name)\n\t\t\t}\n\t\t\tif _, ok := proj.Agent.Options[\"work_dir\"]; ok {\n\t\t\t\treturn fmt.Errorf(\"project %q: multi-workspace mode conflicts with agent work_dir (use base_dir instead)\", proj.Name)\n\t\t\t}\n\t\t}\n\t\tif proj.ResetOnIdleMins != nil && *proj.ResetOnIdleMins < 0 {\n\t\t\treturn fmt.Errorf(\"config: %s.reset_on_idle_mins must be >= 0\", prefix)\n\t\t}\n\t\tif proj.AgentSessionIdleTimeoutMins != nil && *proj.AgentSessionIdleTimeoutMins < 0 {","sourceCodeStart":1017,"sourceCodeEnd":1053,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/config/config.go#L1017-L1053","documentation":"A project must be attached to at least one messaging platform via [[projects.platforms]]. The validator skips this check only in permissive mode (permissive == true, used for partial validation); otherwise a project with zero platforms is rejected since messages would have nowhere to arrive or be replied to.","triggerScenarios":"Loading a full (non-permissive) config where a [[projects]] block has no [[projects.platforms]] sub-tables, or they were all commented out, making len(proj.Platforms) == 0.","commonSituations":"Creating a project intended for later use but leaving it unattached; commenting out a platform while debugging credentials and forgetting to restore it; template configs with the platforms section omitted.","solutions":["Add at least one [[projects.platforms]] block with a type under the failing project","Restore a commented-out [[projects.platforms]] entry","If this is a dry-run/partial load, use the permissive validation path if available"],"exampleFix":"// before\n[[projects]]\nname = \"my-app\"\nagent.type = \"claudecode\"\n// after\n[[projects]]\nname = \"my-app\"\nagent.type = \"claudecode\"\n[[projects.platforms]]\ntype = \"feishu\"","handlingStrategy":"validation","validationCode":"for i, p := range cfg.Projects {\n    if len(p.Platforms) == 0 {\n        return fmt.Errorf(\"projects[%d] has no platforms\", i)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never commit a project block without at least one [[projects.platforms]]","Avoid commenting out the only platform of a project long-term","Validate config after every edit"],"tags":["config","validation","go"],"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-14T05:17:10.506Z"}