{"record":{"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":"exception","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/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L479-L515","documentation":"Raised by Redis.acl_setuser() when an entry in the `passwords` list does not begin with '+' (add) or '-' (remove). Each plain-text password must be prefixed to tell Redis whether to add or remove it from the user. The library encodes each password and inspects the first byte; entries missing the prefix are rejected before the command is built.","triggerScenarios":"Calling client.acl_setuser('alice', passwords=['secret']) (no prefix), passwords=['secret', '+other'] (only some prefixed), or passwords=['=secret'] (wrong prefix). A single string is accepted for convenience but still needs the prefix.","commonSituations":"Assuming the client adds an implicit '+' for you; passing raw user-entered passwords; mixing prefixed and unprefixed entries in a list.","solutions":["Prefix every password entry with '+' to add or '-' to remove, e.g. '+secret'.","If accepting raw input from users, prepend '+' programmatically: '+' + raw_password.","Validate the prefix in your config/form layer before calling acl_setuser."],"exampleFix":"# before\nclient.acl_setuser('alice', passwords=['secret'])\n# after\nclient.acl_setuser('alice', passwords=['+secret'])","handlingStrategy":"validation","validationCode":"def normalize_passwords(passwords):\n    out = []\n    for p in list_or_args(passwords, []):\n        if not (p.startswith('+') or p.startswith('-')):\n            p = '+' + p  # default to add\n        out.append(p)\n    return out\n\ndef safe_acl_setuser_passwords(client, username, passwords):\n    return client.acl_setuser(username, passwords=normalize_passwords(passwords))","typeGuard":"def is_prefixed_password(p) -> bool:\n    return isinstance(p, str) and len(p) > 1 and p[0] in '+-'","tryCatchPattern":"from redis.exceptions import DataError\ntry:\n    client.acl_setuser('alice', passwords=passwords)\nexcept DataError as e:\n    if 'must be prefixed' in str(e):\n        passwords = ['+' + p if not p[:1] in '+-' else p for p in passwords]\n        client.acl_setuser('alice', passwords=passwords)\n    else:\n        raise","preventionTips":["Always prefix password entries with '+'/'-' in config and forms.","Wrap acl_setuser in a helper that enforces the prefix convention.","Document the convention for operators editing ACL config files."],"tags":["acl","validation","acl-setuser","passwords","input-validation","prefix"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}