redis/redis-py · error · RedisError

Invalid SSL Certificate Requirements Flag

Error message

Invalid SSL Certificate Requirements Flag: {cert_reqs}

What it means

Raised as RedisError inside RedisSSLContext.__init__ when ssl_cert_reqs is passed as a string that is not one of 'none', 'optional', or 'required' (case-sensitive lowercase keys). The mapping is fixed; any other string value aborts context construction before the SSLContext is created.

Solutions

  1. Use one of the exact lowercase strings: 'none', 'optional', or 'required'.
  2. Or pass the ssl module constant directly: ssl_cert_reqs=ssl.CERT_REQUIRED.
  3. Double-check the value when it comes from env/config: normalize to lowercase before passing.

Example fix

// before
r = redis.asyncio.Redis(host=h, ssl=True, ssl_cert_reqs='CERT_REQUIRED')
// after
import ssl
r = redis.asyncio.Redis(host=h, ssl=True, ssl_cert_reqs='required')  # or ssl.CERT_REQUIRED
Defensive patterns

Strategy: validation

Validate before calling

import ssl

_VALID = {'none': ssl.CERT_NONE, 'optional': ssl.CERT_OPTIONAL, 'required': ssl.CERT_REQUIRED}

def normalize_cert_reqs(v: str) -> str:
    if isinstance(v, str) and v.lower() in _VALID:
        return v.lower()
    raise ValueError(f"cert_reqs must be one of {sorted(_VALID)}")

Type guard

from redis.exceptions import RedisError

def is_bad_cert_reqs(exc: BaseException) -> bool:
    return isinstance(exc, RedisError) and 'Certificate Requirements Flag' in str(exc)

Try / catch

from redis.exceptions import RedisError

for candidate in ('required', ssl.CERT_REQUIRED):
    try:
        r = redis.asyncio.Redis(host=h, ssl=True, ssl_cert_reqs=candidate)
        break
    except RedisError as e:
        if 'Certificate Requirements Flag' not in str(e):
            raise

Prevention

When it happens

Trigger: Passing ssl_cert_reqs='CERT_REQUIRED', 'Required', 'yes', '1', or any non-canonical token. Common via from_url with ssl_cert_reqs=<wrong> in the query string, or by passing the ssl module constant's string repr.

Common situations: Confusing ssl.CERT_REQUIRED (int 2) with the string 'CERT_REQUIRED'; copy-pasting a config that used the enum name instead of the library's lowercase keyword; typos; case mismatch ('Required' vs 'required').

Understand the failure class

Related errors


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

Appendix: source

Thrown at redis/asyncio/connection.py:1641

        min_version: Optional[TLSVersion] = None,
        ciphers: Optional[str] = None,
        password: Optional[str] = None,
    ):
        if not SSL_AVAILABLE:
            raise RedisError("Python wasn't built with SSL support")

        self.keyfile = keyfile
        self.certfile = certfile
        if cert_reqs is None:
            cert_reqs = ssl.CERT_NONE
        elif isinstance(cert_reqs, str):
            CERT_REQS = {  # noqa: N806
                "none": ssl.CERT_NONE,
                "optional": ssl.CERT_OPTIONAL,
                "required": ssl.CERT_REQUIRED,
            }
            if cert_reqs not in CERT_REQS:
                raise RedisError(
                    f"Invalid SSL Certificate Requirements Flag: {cert_reqs}"
                )
            cert_reqs = CERT_REQS[cert_reqs]
        self.cert_reqs = cert_reqs
        self.include_verify_flags = include_verify_flags
        self.exclude_verify_flags = exclude_verify_flags
        self.ca_certs = ca_certs
        self.ca_data = ca_data
        self.ca_path = ca_path
        self.check_hostname = (
            check_hostname if self.cert_reqs != ssl.CERT_NONE else False
        )
        self.min_version = min_version
        self.ciphers = ciphers
        self.password = password
        self.context: Optional[SSLContext] = None

    def get(self) -> SSLContext:

View on GitHub (pinned to 6a6b581b48)