{"id":"2493cab3609ed1f2","repo":"redis/redis-py","slug":"password-i-must-be-prefixed-with-a-to-add-or","errorCode":null,"errorMessage":"Password {i} must be prefixed with a \"+\" to add or a \"-\" to remove","messagePattern":"Password (.+?) must be prefixed with a \"\\+\" to add or a \"-\" to remove","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":497,"sourceCode":"            pieces.append(b\"off\")\n\n        if (passwords or hashed_passwords) and nopass:\n            raise DataError(\n                \"Cannot set 'nopass' and supply 'passwords' or 'hashed_passwords'\"\n            )\n\n        if passwords:\n            # as most users will have only one password, allow remove_passwords\n            # to be specified as a simple string or a list\n            passwords = list_or_args(passwords, [])\n            for i, password in enumerate(passwords):\n                password = encoder.encode(password)\n                if password.startswith(b\"+\"):\n                    pieces.append(b\">%s\" % password[1:])\n                elif password.startswith(b\"-\"):\n                    pieces.append(b\"<%s\" % password[1:])\n                else:\n                    raise DataError(\n                        f\"Password {i} must be prefixed with a \"\n                        f'\"+\" to add or a \"-\" to remove'\n                    )\n\n        if hashed_passwords:\n            # as most users will have only one password, allow remove_passwords\n            # to be specified as a simple string or a list\n            hashed_passwords = list_or_args(hashed_passwords, [])\n            for i, hashed_password in enumerate(hashed_passwords):\n                hashed_password = encoder.encode(hashed_password)\n                if hashed_password.startswith(b\"+\"):\n                    pieces.append(b\"#%s\" % hashed_password[1:])\n                elif hashed_password.startswith(b\"-\"):\n                    pieces.append(b\"!%s\" % hashed_password[1:])\n                else:\n                    raise DataError(\n                        f\"Hashed password {i} must be prefixed with a \"\n                        f'\"+\" to add or a \"-\" to remove'","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/core.py#L479-L515","documentation":"Raised by acl_setuser() as a DataError when an entry in the passwords iterable does not start with '+' (add) or '-' (remove). Each password must carry an explicit add/remove prefix because ACL SETUSER encodes them as >pwd / <pwd respectively. The 0-based index i of the offending entry is included. See redis/commands/core.py:490-500.","triggerScenarios":"Calling r.acl_setuser(username, passwords=['secret']) (no prefix), or passwords=['+good', 'bad'] where the second entry lacks a prefix. A single prefixed string is also accepted via list_or_args.","commonSituations":"Storing passwords without prefixes and passing them straight through; UI/config that collects bare passwords; assuming the client adds '+' implicitly like some other tools.","solutions":["Prefix each password with '+' to add or '-' to remove, e.g. ['+secret'].","If you only ever add, normalize: passwords = ['+' + p for p in raw_passwords].","Validate prefixes in your config loader so the error never reaches the client."],"exampleFix":"# before\nr.acl_setuser('alice', enabled=True, passwords=['hunter2', '2ndpwd'])\n# after\nr.acl_setuser('alice', enabled=True, passwords=['+hunter2', '+2ndpwd'])","handlingStrategy":"validation","validationCode":"def _prefixed(items):\n    for i, p in enumerate(items):\n        if p[:1] not in ('+', '-'):\n            raise ValueError(f'password {i} needs +/- prefix')\n    return items\nclient.acl_setuser(username, passwords=_prefixed(passwords or []))","typeGuard":"def passwords_are_prefixed(passwords) -> bool:\n    return all(p[:1] in ('+', '-') for p in (passwords or []))","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    client.acl_setuser(username, passwords=passwords)\nexcept DataError:\n    passwords = ['+' + p for p in passwords]  # assume add\n    client.acl_setuser(username, passwords=passwords)","preventionTips":["Normalize bare passwords to '+' prefixed at the config layer.","Store the +/- sign alongside each password in your ACL model."],"tags":["acl","validation","setuser","password","prefix"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}