{"record":{"id":"1ca7565af74c8b03","repo":"HKUDS/DeepTutor","slug":"invalid-role-role-r-must-be-admin-or-user","errorCode":null,"errorMessage":"Invalid role: {role!r}. Must be 'admin' or 'user'.","messagePattern":"Invalid role: (.+?)\\. Must be 'admin' or 'user'\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/auth.py","lineNumber":182,"sourceCode":"    Remove a user from the store. Returns True if the user existed.\n\n    \"\"\"\n    from deeptutor.multi_user.identity import delete_user as _delete_user\n\n    if not _delete_user(username):\n        return False\n    logger.info(\"User '%s' deleted\", username)\n    return True\n\n\ndef set_role(username: str, role: str) -> bool:\n    \"\"\"\n    Change the role for an existing user. Returns True on success.\n\n    Valid roles: 'admin', 'user'.\n    \"\"\"\n    if role not in (\"admin\", \"user\"):\n        raise ValueError(f\"Invalid role: {role!r}. Must be 'admin' or 'user'.\")\n\n    from deeptutor.multi_user.identity import set_role as _set_role\n\n    if not _set_role(username, role):  # type: ignore[arg-type]\n        return False\n    logger.info(f\"User '{username}' role updated to {role!r}\")\n    return True\n\n\ndef set_avatar(username: str, avatar: str) -> bool:\n    \"\"\"\n    Update the avatar marker for an existing user. Returns True on success.\n\n    The marker is either '' (deterministic fallback), 'icon:<name>:<color>',\n    or 'img:<version>' (managed by the avatar upload endpoint).\n    \"\"\"\n    from deeptutor.multi_user.identity import set_avatar as _set_avatar\n","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/auth.py#L164-L200","documentation":"set_role in deeptutor.services.auth only accepts the two literal roles 'admin' and 'user'; any other string raises ValueError. It is a public wrapper around the multi-user identity store's set_role.","triggerScenarios":"Calling auth.set_role(username, role) with values like 'superuser', 'moderator', 'ADMIN' (case matters), or an empty string.","commonSituations":"Scripts promoting users assuming roles like 'root' or 'owner' exist; case-sensitivity bugs ('Admin'); role strings loaded from a config/env var with trailing whitespace; enum drift after role vocabulary changes upstream.","solutions":["Use exactly 'admin' or 'user' (lowercase)","Strip/normalize input: role.strip().lower() before calling","If loading roles from config, validate against ('admin','user') at load time and fail fast with a clear config error"],"exampleFix":"# before\nset_role(\"alice\", \"Admin\")\n# after\nset_role(\"alice\", \"admin\")","handlingStrategy":"validation","validationCode":"VALID_ROLES = (\"admin\", \"user\")\nrole = role.strip().lower() if isinstance(role, str) else role\nif role not in VALID_ROLES:\n    raise ValueError(f\"role must be one of {VALID_ROLES}\")\nset_role(username, role)","typeGuard":"from typing import Literal\nRole = Literal[\"admin\", \"user\"]\ndef is_role(value: str) -> TypeGuard[Role]:\n    return value in (\"admin\", \"user\")","tryCatchPattern":"try:\n    set_role(user, role)\nexcept ValueError as e:\n    if \"Invalid role\" in str(e):\n        role = role.strip().lower()\n        set_role(user, role) if is_role(role) else fail()","preventionTips":["Normalize role strings (strip+lower) at the input boundary","Type role as Literal['admin','user'] in calling code","Validate roles loaded from config/env before use"],"tags":["auth","roles","validation","user-management"],"backgroundTag":"invalid-enum-value","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}