redis/redis-py · error · ValueError

Driver version must not be None

Error message

Driver version must not be None

What it means

add_upstream_driver (redis/driver_info.py:125) rejects a None driver_version with ValueError, mirroring the None-name guard. The version is later formatted as driver_v{version} in the LIB-NAME, so None would corrupt the encoded string. After this check the version still passes _validate_no_invalid_chars (error 423).

Solutions

  1. Resolve a real version string (fall back to importlib.metadata or a hardcoded __version__) before registering the upstream driver.
  2. Skip registration entirely if the version cannot be determined, rather than passing None.
  3. Fail loud at startup (assert version is not None) so misconfigured environments are caught immediately.

Example fix

// before
info.add_upstream_driver('mydriver', getattr(sys.modules['__main__'], 'VERSION', None))
// after
ver = getattr(sys.modules['__main__'], 'VERSION', None) or '0.0.0'
info.add_upstream_driver('mydriver', ver)
Defensive patterns

Strategy: validation

Validate before calling

def resolve_version() -> str:
    try:
        return importlib.metadata.version('mypkg')
    except importlib.metadata.PackageNotFoundError:
        return '0.0.0'

Type guard

def has_version(v) -> bool:
    return isinstance(v, str) and len(v) > 0

Prevention

When it happens

Trigger: Calling driver_info.add_upstream_driver('mydriver', None), or forwarding an unset version constant (e.g. importlib.metadata.version raising PackageNotFoundError and the code defaulting to None).

Common situations: Reading the version from package metadata at import time in an environment where the package is not installed in editable/normal form (so the version lookup returns None); a release script that did not inject the version.

Related errors


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

Appendix: source

Thrown at redis/driver_info.py:125

        """Return a copy of the upstream driver entries.

        Each entry is in the form ``"driver-name_vversion"``.
        """

        return list(self._upstream)

    def add_upstream_driver(
        self, driver_name: str, driver_version: str
    ) -> "DriverInfo":
        """Add an upstream driver to this instance and return self.

        The most recently added driver appears first in :pyattr:`formatted_name`.
        """

        if driver_name is None:
            raise ValueError("Driver name must not be None")
        if driver_version is None:
            raise ValueError("Driver version must not be None")

        _validate_driver_name(driver_name)
        _validate_driver_version(driver_version)

        entry = _format_driver_entry(driver_name, driver_version)
        # insert at the beginning so latest is first
        self._upstream.insert(0, entry)
        return self

    @property
    def formatted_name(self) -> Optional[str]:
        """Return the base name with upstream drivers encoded, if any.

        With no upstream drivers, this is just :pyattr:`name`. Otherwise::

            name(driver1_vX;driver2_vY)
        """

View on GitHub (pinned to 6a6b581b48)