chenhg5/cc-connect · critical
tuitui: app_id and app_secret are required
Error message
tuitui: app_id and app_secret are required
What it means
The TuiTui platform constructor New() requires app_id and app_secret options; one or both are empty. Without these credentials the platform cannot authenticate with the TuiTui API, so construction fails fast at startup rather than at first request.
Solutions
- Set both app_id and app_secret in the tuitui platform config block.
- Verify the keys are in the correct TOML table for the tuitui platform.
- If using env-based secrets, ensure they are loaded into the opts map before New() is called.
- Check key spelling against config.example.toml.
Example fix
// before [platform.tuitui] api_base = "https://api.example.com" // after [platform.tuitui] app_id = "your-app-id" app_secret = "your-app-secret" api_base = "https://api.example.com"
Defensive patterns
Strategy: validation
Validate before calling
cfg := raw["platform.tuitui"].(map[string]any)
for _, k := range []string{"app_id", "app_secret"} {
if v, _ := cfg[k].(string); strings.TrimSpace(v) == "" {
return fmt.Errorf("tuitui config missing %s", k)
}
} Type guard
func tuituiCredsPresent(opts map[string]any) bool {
id, _ := opts["app_id"].(string)
sec, _ := opts["app_secret"].(string)
return strings.TrimSpace(id) != "" && strings.TrimSpace(sec) != ""
} Try / catch
plat, err := tuitui.New(opts)
if err != nil && strings.Contains(err.Error(), "app_id and app_secret are required") {
return fmt.Errorf("startup aborted: fill in tuitui app_id/app_secret in config.toml")
} Prevention
- Fill in both credential keys when copying config.example.toml
- Validate the full platform config at boot before creating platforms
- Inject secrets via env and assert their presence before building the opts map
- Use a config linter/checksum to catch partially copied config blocks
When it happens
Trigger: Config TOML [platform.tuitui] block missing app_id or app_secret keys; keys present but empty strings; values set under the wrong table so opts never contains them; opts map built programmatically without these keys.
Common situations: Fresh deployment with a copied example config not fully filled in; secrets injected via env vars not wired into the opts map; typo in key name (e.g. appid); using another platform's config template.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- tuitui: invalid group_policy
- wecom: corp_id, corp_secret, and agent_id are required
- acp: agent option "cmd" or "command" is required (path or…
- acp: command not found in PATH
- api returned status
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/415b0cdd72186c42.
Report an issue: GitHub.
Appendix: source
Thrown at platform/tuitui/tuitui.go:109
_ core.FormattingInstructionProvider = (*Platform)(nil)
)
// New creates a TuiTui platform from config options.
//
// [[projects.platforms]]
// type = "tuitui"
// [projects.platforms.options]
// app_id = "${TUITUI_APP_ID}"
// app_secret = "${TUITUI_APP_SECRET}"
// allow_from = "*" # user accounts, comma-separated
// group_allow_from = "123,456" # group IDs, team IDs, or channel IDs
// ignore_from = "bot-xxx" # bot accounts to ignore when webhook echoes outbound messages
// require_mention = true # group chats and channel posts require @bot
func New(opts map[string]any) (core.Platform, error) {
appID, _ := opts["app_id"].(string)
appSecret, _ := opts["app_secret"].(string)
if appID == "" || appSecret == "" {
return nil, fmt.Errorf("tuitui: app_id and app_secret are required")
}
apiBase, _ := opts["api_base"].(string)
if apiBase == "" {
apiBase = defaultAPIBase
}
wsBase, _ := opts["ws_base"].(string)
if wsBase == "" {
wsBase = defaultWSBase
}
allowFrom, _ := opts["allow_from"].(string)
core.CheckAllowFrom("tuitui", allowFrom)
groupAllowFrom, _ := opts["group_allow_from"].(string)
ignoreFrom, _ := opts["ignore_from"].(string)
groupPolicy, _ := opts["group_policy"].(string)
if groupPolicy == "" {
groupPolicy = "allowlist"
}
groupPolicy = strings.ToLower(strings.TrimSpace(groupPolicy))View on GitHub (pinned to 4000b2338a)