chenhg5/cc-connect · error
bot_token is required (format: app_key:app_secret)
Error message
bot_token is required (format: app_key:app_secret)
What it means
Returned when opts.BotToken is empty or does not contain a colon in a valid app_key:app_secret position (colon at index 0 or at the very end). The yuanbao platform authenticates via a combined token string, and this check enforces that format before touching the config file.
Source
Thrown at config/config.go:2707
AllowFrom string
}
// SaveYuanbaoPlatformCredentials updates bot_token (and optional fields)
// for a project's Yuanbao platform.
func SaveYuanbaoPlatformCredentials(opts YuanbaoCredentialUpdateOptions) (*YuanbaoCredentialUpdateResult, error) {
configMu.Lock()
defer configMu.Unlock()
if ConfigPath == "" {
return nil, fmt.Errorf("config path not set")
}
if strings.TrimSpace(opts.ProjectName) == "" {
return nil, fmt.Errorf("project name is required")
}
botToken := strings.TrimSpace(opts.BotToken)
idx := strings.Index(botToken, ":")
if botToken == "" || idx <= 0 || idx >= len(botToken)-1 {
return nil, fmt.Errorf("bot_token is required (format: app_key:app_secret)")
}
if opts.PlatformIndex < 0 {
return nil, fmt.Errorf("platform index must be >= 0")
}
data, err := os.ReadFile(ConfigPath)
if err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
raw := string(data)
cfg := &Config{}
if err := toml.Unmarshal(data, cfg); err != nil {
return nil, fmt.Errorf("parse config: %w", err)
}
projectIdx := -1
for i := range cfg.Projects {
if cfg.Projects[i].Name == opts.ProjectName {View on GitHub (pinned to 4000b2338a)
Solutions
- Provide the token as `app_key:app_secret` with both parts non-empty, e.g. opts.BotToken = "mykey:mysecret"
- Check the env var or secret store actually contains the colon-separated value: echo "$YUANBAO_BOT_TOKEN" | grep ':'
- Regenerate/re-copy credentials from the yuanbao console if the secret half is missing
Example fix
// before
opts.BotToken = os.Getenv("YUANBAO_KEY") // only app key, no colon
// after
opts.BotToken = os.Getenv("YUANBAO_KEY") + ":" + os.Getenv("YUANBAO_SECRET") Defensive patterns
Strategy: validation
Validate before calling
tok := strings.TrimSpace(opts.BotToken)
if i := strings.Index(tok, ":"); tok == "" || i <= 0 || i >= len(tok)-1 {
return fmt.Errorf("bot_token must be app_key:app_secret")
} Type guard
func validBotToken(tok string) bool {
tok = strings.TrimSpace(tok)
i := strings.Index(tok, ":")
return tok != "" && i > 0 && i < len(tok)-1
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "bot_token is required") {
slog.Error("check YUANBAO_BOT_TOKEN format: expected app_key:app_secret")
return err
}
return err
} Prevention
- Store app_key and app_secret separately and join them programmatically
- Never pass the token through shell interpolation that can drop the secret half
- Validate credentials once at startup
When it happens
Trigger: Calling the API with BotToken left empty, BotToken set to just "app_key" (no colon), ":app_secret", or a token made of only whitespace after trimming.
Common situations: Copying only the app key into config; shell quoting dropping the secret part of the token; an env var like YUANBAO_BOT_TOKEN unset so the value interpolates to empty; using a full URL or JWT instead of the app_key:app_secret pair.
Related errors
- app_id and app_secret are required
- token is required
- yuanbao: bot_token is required (format: app_key:app_secret)
- app_id/app_secret are required
- tmux: 'session' option is required (name of the tmux session
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/a4422ef79f6524cb.
Report an issue: GitHub.