chenhg5/cc-connect · error
user %q appears in both role %q and %q
Error message
user %q appears in both role %q and %q
What it means
ValidateRoleInputs enforces that each concrete user ID appears in at most one role. It lowercases user IDs for comparison (case-insensitive) and reports both the offending user and the two conflicting role names when a duplicate is found. This prevents ambiguous role resolution.
Source
Thrown at core/user_roles.go:223
if len(roles) == 0 {
return fmt.Errorf("no roles defined")
}
wildcardCount := 0
seenUserIDs := make(map[string]string) // userID → role name
roleNames := make(map[string]bool, len(roles))
for _, ri := range roles {
roleNames[ri.Name] = true
if len(ri.UserIDs) == 0 {
return fmt.Errorf("role %q has empty user_ids", ri.Name)
}
for _, uid := range ri.UserIDs {
if uid == "*" {
wildcardCount++
continue
}
lower := strings.ToLower(uid)
if prev, dup := seenUserIDs[lower]; dup {
return fmt.Errorf("user %q appears in both role %q and %q", uid, prev, ri.Name)
}
seenUserIDs[lower] = ri.Name
}
}
if wildcardCount > 1 {
return fmt.Errorf("wildcard user_ids=[\"*\"] appears in multiple roles")
}
if defaultRole != "" {
if !roleNames[defaultRole] {
return fmt.Errorf("default_role %q does not match any defined role", defaultRole)
}
}
return nil
}
// Stop terminates all per-role rate limiter goroutines. Nil-receiver safe.
func (m *UserRoleManager) Stop() {
if m == nil {View on GitHub (pinned to 4000b2338a)
Solutions
- Remove the user from one of the two roles named in the error
- Unify user ID casing across roles to make the intent explicit (matching is case-insensitive either way)
- Pre-process the payload in the caller to detect cross-role duplicates and surface a friendlier message
Example fix
// before
roles := []core.RoleInput{
{Name: "admin", UserIDs: []string{"Alice"}},
{Name: "dev", UserIDs: []string{"alice"}},
}
// after
roles := []core.RoleInput{
{Name: "admin", UserIDs: []string{"alice"}},
{Name: "dev", UserIDs: []string{"bob"}},
} Defensive patterns
Strategy: validation
Validate before calling
seen := map[string]string{}
for _, r := range roles {
for _, u := range r.UserIDs {
k := strings.ToLower(u)
if _, dup := seen[k]; dup {
return fmt.Errorf("duplicate user %q", u)
}
seen[k] = r.Name
}
}
core.ValidateRoleInputs(defaultRole, roles) Prevention
- Treat user IDs case-insensitively everywhere
- Deduplicate users across roles before saving configs
- Avoid adding a user to a new role without removing them from the old one
When it happens
Trigger: Calling ValidateRoleInputs where two roles both list the same user ID (in any letter casing, e.g. "Alice" in role A and "alice" in role B). Wildcard "*" entries bypass this check.
Common situations: Merging two project-user configs that each assigned the same user; copy-pasting a user into a new role without removing them from the old one; a team member added to both 'admin' and 'developer'.
Related errors
- config: %s.users has no roles defined
- config: %s.users.roles.%s has empty user_ids
- provider %q already exists in project %q
- global provider %q already exists
- no roles defined
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/f229c70fb0b287c2.
Report an issue: GitHub.