getredash/redash · error
Must be admin to change groups membership.
Error message
Must be admin to change groups membership.
What it means
Raised by Redash's user update endpoint (POST /api/users/<id>) when the request body contains group_ids but the authenticated user lacks the admin permission. Only admins may change a user's group memberships, so the handler aborts with HTTP 403 before applying any updates.
Source
Thrown at redash/handlers/users.py:226
user = models.User.get_by_id_and_org(user_id, self.current_org)
req = request.get_json(True)
params = project(req, ("email", "name", "password", "old_password", "group_ids"))
if "password" in params and "old_password" not in params:
abort(403, message="Must provide current password to update password.")
if "old_password" in params and not user.verify_password(params["old_password"]):
abort(403, message="Incorrect current password.")
if "password" in params:
user.hash_password(params.pop("password"))
params.pop("old_password")
if "group_ids" in params:
if not self.current_user.has_permission("admin"):
abort(403, message="Must be admin to change groups membership.")
for group_id in params["group_ids"]:
try:
models.Group.get_by_id_and_org(group_id, self.current_org)
except NoResultFound:
abort(400, message="Group id {} is invalid.".format(group_id))
if len(params["group_ids"]) == 0:
params.pop("group_ids")
if "email" in params:
require_allowed_email(params["email"])
email_address_changed = "email" in params and params["email"] != user.email
needs_to_verify_email = email_address_changed and settings.email_server_is_configured()
if needs_to_verify_email:
user.is_email_verified = False
View on GitHub (pinned to ca79fe988d)
Solutions
- Remove group_ids from the request payload if you only intend to update profile fields (name, email, password)
- Authenticate with an account/API key that belongs to the admin group of the target organization
- If self-service group management is intended, have an admin perform the change or add the caller to the admin group
Example fix
# before
requests.post(f"{url}/api/users/{uid}", json={"name": "x", "group_ids": [1,2]}, headers=hdrs) # 403
# after
requests.post(f"{url}/api/users/{uid}", json={"name": "x"}, headers=hdrs) Defensive patterns
Strategy: validation
Validate before calling
me = requests.get(f"{url}/api/session", headers=hdrs).json()
# or fetch current user and check group membership
is_admin = any(g["type"] == "admin" or "admin" in g.get("name", "").lower()
for g in requests.get(f"{url}/api/groups", headers=hdrs).json())
if not is_admin:
payload.pop("group_ids", None) Prevention
- Only include group_ids in user-update payloads when strictly necessary
- Keep a dedicated admin API key for user-management scripts and a personal key for reads
- Check the caller's groups via /api/groups before attempting membership changes
When it happens
Trigger: POST (or PUT) to /api/users/<user_id> with a JSON body containing a "group_ids" key while authenticated as a non-admin user (e.g. a regular user editing their own profile and including group_ids, or a disabled/limited API key without admin access).
Common situations: Client UI sending the full user object (including group_ids it previously read) on profile save; automation scripts reusing a personal (non-admin) API key for user management; org members assuming self-edit covers group membership.
Related errors
- Group id {} is invalid.
- You don't have permission to edit this resource.
- You do not have access to data source: %s.
- You do not have access to query id %s.
- Python query helpers require a current user.
AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28).
Data as JSON: /api/errors/05f783104747c2fe.
Report an issue: GitHub.