redis/redis-py · error · DataError

Password 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 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.

Solutions

  1. Prefix every password entry with '+' to add or '-' to remove, e.g. '+secret'.
  2. If accepting raw input from users, prepend '+' programmatically: '+' + raw_password.
  3. Validate the prefix in your config/form layer before calling acl_setuser.

Example fix

# before
client.acl_setuser('alice', passwords=['secret'])
# after
client.acl_setuser('alice', passwords=['+secret'])
Defensive patterns

Strategy: validation

Validate before calling

def normalize_passwords(passwords):
    out = []
    for p in list_or_args(passwords, []):
        if not (p.startswith('+') or p.startswith('-')):
            p = '+' + p  # default to add
        out.append(p)
    return out

def safe_acl_setuser_passwords(client, username, passwords):
    return client.acl_setuser(username, passwords=normalize_passwords(passwords))

Type guard

def is_prefixed_password(p) -> bool:
    return isinstance(p, str) and len(p) > 1 and p[0] in '+-'

Try / catch

from redis.exceptions import DataError
try:
    client.acl_setuser('alice', passwords=passwords)
except DataError as e:
    if 'must be prefixed' in str(e):
        passwords = ['+' + p if not p[:1] in '+-' else p for p in passwords]
        client.acl_setuser('alice', passwords=passwords)
    else:
        raise

Prevention

When it happens

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

Common situations: Assuming the client adds an implicit '+' for you; passing raw user-entered passwords; mixing prefixed and unprefixed entries in a list.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/2493cab3609ed1f2. Report an issue: GitHub.

Appendix: 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 6a6b581b48)