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

  1. Provide the token as `app_key:app_secret` with both parts non-empty, e.g. opts.BotToken = "mykey:mysecret"
  2. Check the env var or secret store actually contains the colon-separated value: echo "$YUANBAO_BOT_TOKEN" | grep ':'
  3. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/a4422ef79f6524cb. Report an issue: GitHub.