getredash/redash · error
Group id {} is invalid.
Error message
Group id {} is invalid. What it means
Raised by the user update endpoint when the request's group_ids array references a group that does not exist within the current organization. The handler verifies each id via models.Group.get_by_id_and_org and aborts with HTTP 400 on the first id that yields NoResultFound.
Source
Thrown at redash/handlers/users.py:232
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
try:
self.update_model(user, params)
models.db.session.commit()
if needs_to_verify_email:
send_verify_email(user, self.current_org)View on GitHub (pinned to ca79fe988d)
Solutions
- Fetch valid ids first via GET /api/groups and use ids from that response
- Verify each id exists in the same organization as the user being edited
- Drop deleted/stale ids from group_ids before resubmitting
Example fix
# before
{"group_ids": [1, 999]} # 400: Group id 999 is invalid.
# after
groups = requests.get(f"{url}/api/groups", headers=hdrs).json()
valid = {g["id"] for g in groups}
{"group_ids": [g for g in [1, 999] if g in valid]} Defensive patterns
Strategy: validation
Validate before calling
valid = {g["id"] for g in requests.get(f"{url}/api/groups", headers=hdrs).json()}
payload["group_ids"] = [gid for gid in payload.get("group_ids", []) if gid in valid]
if not payload["group_ids"]:
payload.pop("group_ids", None) Type guard
def is_valid_group_id(groups, gid):
return isinstance(gid, int) and gid in {g["id"] for g in groups} Prevention
- Always resolve group ids from GET /api/groups at request time instead of hardcoding
- Re-fetch group lists after org/group restructuring
- Treat any 400 mentioning 'Group id' as a signal to refresh cached ids
When it happens
Trigger: POST to /api/users/<id> with group_ids containing an id that is deleted, belongs to a different organization, or is a plain typo (e.g. [999]); passing group names or slugs instead of numeric ids also produces it.
Common situations: Stale cached group lists after groups were deleted or re-created; scripts copy-pasting group ids between environments (staging vs prod orgs); sending strings like "group_admin" instead of the numeric id.
Related errors
- Bad email address.
- Must provide current password to update password.
- Must be admin to change groups membership.
- Error updating record
- Missing `rows` field in `result` dict.
AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28).
Data as JSON: /api/errors/13ce30a5b37b8fd9.
Report an issue: GitHub.