redis/redis-py · error · DataError

Password {i} must be prefixed with a "+" to add or a "-" to

Error message

Password {i} must be prefixed with a "+" to add or a "-" to remove

What it means

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.

Source

Thrown at redis/commands/core.py:497

            pieces.append(b"off")

        if (passwords or hashed_passwords) and nopass:
            raise DataError(
                "Cannot set 'nopass' and supply 'passwords' or 'hashed_passwords'"
            )

        if passwords:
            # as most users will have only one password, allow remove_passwords
            # to be specified as a simple string or a list
            passwords = list_or_args(passwords, [])
            for i, password in enumerate(passwords):
                password = encoder.encode(password)
                if password.startswith(b"+"):
                    pieces.append(b">%s" % password[1:])
                elif password.startswith(b"-"):
                    pieces.append(b"<%s" % password[1:])
                else:
                    raise DataError(
                        f"Password {i} must be prefixed with a "
                        f'"+" to add or a "-" to remove'
                    )

        if hashed_passwords:
            # as most users will have only one password, allow remove_passwords
            # to be specified as a simple string or a list
            hashed_passwords = list_or_args(hashed_passwords, [])
            for i, hashed_password in enumerate(hashed_passwords):
                hashed_password = encoder.encode(hashed_password)
                if hashed_password.startswith(b"+"):
                    pieces.append(b"#%s" % hashed_password[1:])
                elif hashed_password.startswith(b"-"):
                    pieces.append(b"!%s" % hashed_password[1:])
                else:
                    raise DataError(
                        f"Hashed password {i} must be prefixed with a "
                        f'"+" to add or a "-" to remove'

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Prefix each password with '+' to add or '-' to remove, e.g. ['+secret'].
  2. If you only ever add, normalize: passwords = ['+' + p for p in raw_passwords].
  3. Validate prefixes in your config loader so the error never reaches the client.

Example fix

# before
r.acl_setuser('alice', enabled=True, passwords=['hunter2', '2ndpwd'])
# after
r.acl_setuser('alice', enabled=True, passwords=['+hunter2', '+2ndpwd'])
Defensive patterns

Strategy: validation

Validate before calling

def _prefixed(items):
    for i, p in enumerate(items):
        if p[:1] not in ('+', '-'):
            raise ValueError(f'password {i} needs +/- prefix')
    return items
client.acl_setuser(username, passwords=_prefixed(passwords or []))

Type guard

def passwords_are_prefixed(passwords) -> bool:
    return all(p[:1] in ('+', '-') for p in (passwords or []))

Try / catch

from redis.exceptions import DataError
try:
    client.acl_setuser(username, passwords=passwords)
except DataError:
    passwords = ['+' + p for p in passwords]  # assume add
    client.acl_setuser(username, passwords=passwords)

Prevention

When it happens

Trigger: 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.

Common situations: Storing passwords without prefixes and passing them straight through; UI/config that collects bare passwords; assuming the client adds '+' implicitly like some other tools.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/2493cab3609ed1f2.json. Report an issue: GitHub.