{"record":{"id":"79eb0bbe899cfd05","repo":"t8y2/dbx","slug":"auth-user-s-already-exists","errorCode":null,"errorMessage":"auth: User %s already exists.","messagePattern":"auth: User (.+?) already exists\\.","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/etcd2-go/auth.go","lineNumber":124,"sourceCode":"\t\treturn nil, err\n\t}\n\tuser, err := requiredString(params, \"user\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpassword, err := requiredString(params, \"password\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tctx, cancel := s.beginOperation()\n\tdefer s.endOperation(cancel)\n\tpayload := v2UserDocument{User: user, Password: password}\n\t_, response, err := client.doJSON(ctx, http.MethodPut, \"/v2/auth/users/\"+escapePathSegment(user), payload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif response != nil && response.StatusCode == http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"auth: User %s already exists.\", user)\n\t}\n\treturn map[string]bool{\"created\": true}, nil\n}\n\nfunc (s *etcd2Session) authUserDelete(params map[string]json.RawMessage) (any, error) {\n\tclient, err := s.activeClient()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tuser, err := requiredString(params, \"user\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tctx, cancel := s.beginOperation()\n\tdefer s.endOperation(cancel)\n\tif _, _, err := client.do(ctx, http.MethodDelete, \"/v2/auth/users/\"+escapePathSegment(user), \"\", nil); err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/etcd2-go/auth.go#L106-L142","documentation":"The etcd2 agent's authUserAdd performs an HTTP PUT to /v2/auth/users/<user> to create a user; the etcd v2 auth API returns 200 for an existing user, so the agent interprets a 200 as 'the user already exists' and surfaces this error instead of reporting success. Creating a duplicate user is rejected to avoid silently overwriting credentials.","triggerScenarios":"Calling auth user add (authUserAdd) for a user name that already exists in the etcd auth user list.","commonSituations":"Re-running provisioning scripts that create users idempotently without checking existence; a previous partially-failed setup already created the user; two operators creating the same username concurrently.","solutions":["Check existence first (list auth users or attempt get) and skip creation if present","Treat this error as idempotent success if the desired password is already set, or delete and re-add the user","Use a new unique username if a separate account is truly needed"],"exampleFix":"// before\nagent.call(\"auth user add\", map[string]any{\"user\": \"alice\", \"password\": pw})\n\n// after\nusers, _ := agent.call(\"auth user list\", nil)\nif !contains(users, \"alice\") {\n    agent.call(\"auth user add\", map[string]any{\"user\": \"alice\", \"password\": pw})\n}","handlingStrategy":"try-catch","validationCode":"// check the user list before adding\nusers, err := agent.Call(\"auth user list\", nil)\nif err == nil && containsUser(users, \"alice\") {\n    return nil // already provisioned\n}","typeGuard":"func isUserExists(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"already exists\")\n}","tryCatchPattern":"_, err := agent.Call(\"auth user add\", map[string]any{\"user\": u, \"password\": pw})\nif isUserExists(err) {\n    return nil // treat as idempotent success or update password instead\n}","preventionTips":["Make provisioning scripts idempotent: check-then-create","Run a single provisioner to avoid concurrent duplicate creation","On redeploys, reuse existing users instead of re-adding"],"tags":["go","etcd","auth","duplicate-resource"],"backgroundTag":"user-already-exists","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}