{"record":{"id":"602a06e2a83ee3b4","repo":"redis/redis-py","slug":"driver-version-must-not-be-none","errorCode":null,"errorMessage":"Driver version must not be None","messagePattern":"Driver version must not be None","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"redis/driver_info.py","lineNumber":125,"sourceCode":"        \"\"\"Return a copy of the upstream driver entries.\n\n        Each entry is in the form ``\"driver-name_vversion\"``.\n        \"\"\"\n\n        return list(self._upstream)\n\n    def add_upstream_driver(\n        self, driver_name: str, driver_version: str\n    ) -> \"DriverInfo\":\n        \"\"\"Add an upstream driver to this instance and return self.\n\n        The most recently added driver appears first in :pyattr:`formatted_name`.\n        \"\"\"\n\n        if driver_name is None:\n            raise ValueError(\"Driver name must not be None\")\n        if driver_version is None:\n            raise ValueError(\"Driver version must not be None\")\n\n        _validate_driver_name(driver_name)\n        _validate_driver_version(driver_version)\n\n        entry = _format_driver_entry(driver_name, driver_version)\n        # insert at the beginning so latest is first\n        self._upstream.insert(0, entry)\n        return self\n\n    @property\n    def formatted_name(self) -> Optional[str]:\n        \"\"\"Return the base name with upstream drivers encoded, if any.\n\n        With no upstream drivers, this is just :pyattr:`name`. Otherwise::\n\n            name(driver1_vX;driver2_vY)\n        \"\"\"\n","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/driver_info.py#L107-L143","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Resolve a real version string (fall back to importlib.metadata or a hardcoded __version__) before registering the upstream driver.","Skip registration entirely if the version cannot be determined, rather than passing None.","Fail loud at startup (assert version is not None) so misconfigured environments are caught immediately."],"exampleFix":"// before\ninfo.add_upstream_driver('mydriver', getattr(sys.modules['__main__'], 'VERSION', None))\n// after\nver = getattr(sys.modules['__main__'], 'VERSION', None) or '0.0.0'\ninfo.add_upstream_driver('mydriver', ver)","handlingStrategy":"validation","validationCode":"def resolve_version() -> str:\n    try:\n        return importlib.metadata.version('mypkg')\n    except importlib.metadata.PackageNotFoundError:\n        return '0.0.0'","typeGuard":"def has_version(v) -> bool:\n    return isinstance(v, str) and len(v) > 0","tryCatchPattern":null,"preventionTips":["Always provide a fallback version string when package metadata may be unavailable.","Skip registration if the version cannot be determined.","Assert the version is non-None at startup in environments where it must exist."],"tags":["driver-info","validation","null-check","upstream-driver"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}