chenhg5/cc-connect · error
config: %s.users: user %q appears in both role %q and %q
Error message
config: %s.users: user %q appears in both role %q and %q
What it means
This validation error is returned while loading/validating the users section of a project's role-based access config. Each user_id may only be assigned to one role; duplicates (compared case-insensitively) are ambiguous so the config is rejected. It prevents silently inconsistent permission resolution where two roles would both claim the same user.
Source
Thrown at config/config.go:1182
return nil
}
if len(u.Roles) == 0 {
return fmt.Errorf("config: %s.users has no roles defined", prefix)
}
wildcardCount := 0
seenUserIDs := make(map[string]string) // userID → role name
for roleName, rc := range u.Roles {
if len(rc.UserIDs) == 0 {
return fmt.Errorf("config: %s.users.roles.%s has empty user_ids", prefix, roleName)
}
for _, uid := range rc.UserIDs {
if uid == "*" {
wildcardCount++
continue
}
lower := strings.ToLower(uid)
if prev, dup := seenUserIDs[lower]; dup {
return fmt.Errorf("config: %s.users: user %q appears in both role %q and %q", prefix, uid, prev, roleName)
}
seenUserIDs[lower] = roleName
}
}
if wildcardCount > 1 {
return fmt.Errorf("config: %s.users: wildcard user_ids=[\"*\"] appears in multiple roles", prefix)
}
if u.DefaultRole != "" {
if _, ok := u.Roles[u.DefaultRole]; !ok {
return fmt.Errorf("config: %s.users.default_role %q does not match any defined role", prefix, u.DefaultRole)
}
}
return nil
}
// SaveActiveProvider persists the active provider name for a project.
// It uses surgical text editing to preserve comments and unknown fields.
func SaveActiveProvider(projectName, providerName string) error {View on GitHub (pinned to 4000b2338a)
Solutions
- Find the role names in the message and remove the duplicate user_id from one of the two roles
- Keep one authoritative role per user; use default_role instead of listing the user in multiple roles
- Search config.toml for the user id case-insensitively to catch case-variant duplicates
- Reload/restart so validation re-runs and confirms the config is accepted
Example fix
// before [[projects.users.roles.admin]] user_ids = ["alice"] [[projects.users.roles.member]] user_ids = ["alice"] // after [[projects.users.roles.admin]] user_ids = ["alice"] [[projects.users.roles.member]] user_ids = ["bob"]
Defensive patterns
Strategy: validation
Validate before calling
func validateNoDupUsers(roles map[string][]string) error {
seen := map[string]string{}
for role, ids := range roles {
for _, id := range ids {
k := strings.ToLower(id)
if prev, ok := seen[k]; ok {
return fmt.Errorf("user %q in %q and %q", id, prev, role)
}
seen[k] = role
}
}
return nil
} Try / catch
if err := cfg.Validate(); err != nil {
if strings.Contains(err.Error(), "appears in both role") {
// fix config before proceeding
}
return err
} Prevention
- Keep a single source of truth for role assignments; generate roles from one user->role map
- Always compare user ids case-insensitively when editing config
- Lint config.toml in CI before deploying role changes
When it happens
Trigger: Calling config load/validate (via the engine startup or LoadConfig) when a project's [[projects.users]] block lists the same user_id string (case-insensitive) under two different roles in u.Roles.
Common situations: Hand-editing config.toml and copy-pasting a user into a second role; a colleague already granted the user admin while you added them as member; case differences ('Alice' vs 'alice') hiding the duplicate.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- tmux: 'session' option is required (name of the tmux session
- config: relay.visibility must be "full", "summary", or "none
- config: at least one [[projects]] entry is required
- config: %s.name is required
- config: %s.agent.type is required
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/f32f0b3fb08c0578.
Report an issue: GitHub.