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

  1. Remove group_ids from the request payload if you only intend to update profile fields (name, email, password)
  2. Authenticate with an account/API key that belongs to the admin group of the target organization
  3. 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

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


AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28). Data as JSON: /api/errors/05f783104747c2fe. Report an issue: GitHub.