router-for-me/CLIProxyAPI · warning

auth id is empty

Error message

auth id is empty

What it means

toggleConfigAPIKeyExcludedAll found a config-API-key auth (coreauth.IsConfigAPIKeyAuth true) whose ID is empty after trimming, so it cannot match the auth against entries in cfg.GeminiKey (and sibling API-key lists) that were assigned stable generated IDs. It errors instead of no-op'ing because the caller explicitly asked to toggle a config API key, and silently skipping would hide the mismatch.

Source

Thrown at internal/api/handlers/management/config_apikey_disable.go:39

		return config.NormalizeExcludedModels(append(append([]string(nil), models...), configAPIKeyDisablePattern))
	}
	filtered := make([]string, 0, len(models))
	for _, item := range models {
		if strings.TrimSpace(item) == configAPIKeyDisablePattern {
			continue
		}
		filtered = append(filtered, item)
	}
	return config.NormalizeExcludedModels(filtered)
}

func toggleConfigAPIKeyExcludedAll(cfg *config.Config, auth *coreauth.Auth, disable bool) (bool, error) {
	if cfg == nil || auth == nil || !coreauth.IsConfigAPIKeyAuth(auth) {
		return false, nil
	}
	authID := strings.TrimSpace(auth.ID)
	if authID == "" {
		return false, fmt.Errorf("auth id is empty")
	}

	idGen := synthesizer.NewStableIDGenerator()

	for i := range cfg.GeminiKey {
		entry := &cfg.GeminiKey[i]
		id, _ := idGen.Next("gemini:apikey", entry.APIKey, entry.BaseURL)
		if id == authID {
			entry.ExcludedModels = setConfigAPIKeyExcludedAll(entry.ExcludedModels, disable)
			return true, nil
		}
	}
	for i := range cfg.InteractionsKey {
		entry := &cfg.InteractionsKey[i]
		id, _ := idGen.Next("gemini-interactions:apikey", entry.APIKey, entry.BaseURL)
		if id == authID {
			entry.ExcludedModels = setConfigAPIKeyExcludedAll(entry.ExcludedModels, disable)
			return true, nil

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. GET the auth record and confirm its id field; re-create the config API key through normal flows so a stable ID is generated
  2. Ensure custom code builds config API key auths with synthesizer.NewStableIDGenerator().Next(...) IDs
  3. If IDs are being lost in storage, fix the store mapping for the ID field
  4. Retry the toggle once the record carries a non-empty ID

Example fix

// before
auth := &coreauth.Auth{Provider: "gemini", APIKey: "..."} // no ID
// after
id, _ := synthesizer.NewStableIDGenerator().Next("gemini:apikey", key, baseURL)
auth := &coreauth.Auth{ID: id, Provider: "gemini", APIKey: "..."}
Defensive patterns

Strategy: type-guard

Validate before calling

if strings.TrimSpace(auth.ID) == "" {
    return errors.New("config API key auth lacks an ID; regenerate the credential")
}

Type guard

func hasAuthID(auth *coreauth.Auth) bool { return auth != nil && strings.TrimSpace(auth.ID) != "" }

Prevention

When it happens

Trigger: Calling the enable/disable (excluded-models) toggle on a synthetic config API key auth record that was constructed without an ID — test fixtures, custom embedders building auth objects directly, or records deserialized from a store that dropped the ID field.

Common situations: Programmatic auth construction bypassing the ID generator; store round-trips stripping the ID; forks changing ID derivation.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/5d22791c4a9060d8. Report an issue: GitHub.