{"record":{"id":"01635852b4a53022","repo":"redis/redis-py","slug":"unsupported-client-type-type-database-client","errorCode":null,"errorMessage":"Unsupported client type: {type(database.client)}","messagePattern":"Unsupported client type: (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/multidb/healthcheck.py","lineNumber":213,"sourceCode":"                        nodes_manager,\n                        \"require_full_coverage\",\n                        getattr(nodes_manager, \"_require_full_coverage\", True),\n                    )\n                    client = AsyncRedisCluster(\n                        host=first_node.host,\n                        port=first_node.port,\n                        dynamic_startup_nodes=nodes_manager._dynamic_startup_nodes,\n                        address_remap=nodes_manager.address_remap,\n                        require_full_coverage=require_full_coverage,\n                        retry=database.client.retry,\n                        **filtered_kwargs,\n                    )\n                else:\n                    raise ValueError(\n                        \"Cluster client has no nodes - cannot create health check client\"\n                    )\n            else:\n                raise TypeError(f\"Unsupported client type: {type(database.client)}\")\n            self._clients[db_id] = client\n\n        return client\n\n    async def close(self) -> None:\n        \"\"\"Close all health check clients.\"\"\"\n        close_tasks = [\n            asyncio.create_task(client.aclose()) for client in self._clients.values()\n        ]\n\n        if close_tasks:\n            await asyncio.gather(*close_tasks, return_exceptions=True)\n\n        self._clients.clear()\n\n    @abstractmethod\n    async def _execute(self, health_check: HealthCheck, database) -> bool:\n        \"\"\"","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/multidb/healthcheck.py#L195-L231","documentation":"Raised as TypeError by AbstractHealthCheckPolicy.get_client() (healthcheck.py:212-213) when the database's client is none of the four supported types (AsyncRedis, SyncRedis, AsyncRedisCluster, SyncRedisCluster). The health-check layer only knows how to derive connection kwargs / startup nodes for those, so an unrecognised client type is rejected rather than probed incorrectly.","triggerScenarios":"Setting MultiDbConfig.client_class (or a Database's client) to a custom/non-standard client class — a third-party Redis wrapper, a mock/stub in tests, or a subclass the policy cannot introspect. The f-string includes type(database.client) to identify the offender.","commonSituations":"Injecting a test double/mock client that is not a Redis subclass; using a custom Redis subclass that does not inherit from one of the supported bases; wrapping the client in a proxy object; version skew where a refactor changed the client class hierarchy.","solutions":["Use one of the supported client classes (redis.asyncio.Redis or redis.asyncio.RedisCluster) as the database client.","If you need a subclass, inherit from AsyncRedis/AsyncRedisCluster so isinstance checks pass.","In tests, use a real AsyncRedis against a test container or fakeredis that subclasses AsyncRedis, not an unrelated Mock.","Inspect the message's type(...) to find which database holds the unsupported client and fix its DatabaseConfig."],"exampleFix":"// before\nclass MyRedis:\n    # does not subclass AsyncRedis\n    ...\ndb_cfg = DatabaseConfig(client_kwargs={})  # MultiDbConfig.client_class = MyRedis\n# health check raises TypeError\n\n// after\nfrom redis.asyncio import Redis\nclass MyRedis(Redis):\n    ...\ndb_cfg = DatabaseConfig(client_kwargs={\"host\": \"redis.local\", \"port\": 6379})\nconfig = MultiDbConfig(databases_config=[db_cfg], client_class=MyRedis)","handlingStrategy":"type-guard","validationCode":"from redis.asyncio import Redis as AsyncRedis, RedisCluster as AsyncRedisCluster\nfrom redis.client import Redis as SyncRedis\nfrom redis.cluster import RedisCluster as SyncRedisCluster\n\ndef client_type_supported(db) -> bool:\n    return isinstance(db.client, (AsyncRedis, SyncRedis, AsyncRedisCluster, SyncRedisCluster))\n\n# before initialize():\nfor db, _ in client.get_databases():\n    assert client_type_supported(db), f\"unsupported client type {type(db.client)!r}\"","typeGuard":"from redis.asyncio import Redis as AsyncRedis, RedisCluster as AsyncRedisCluster\nfrom redis.client import Redis as SyncRedis\nfrom redis.cluster import RedisCluster as SyncRedisCluster\n\ndef is_supported_client(client) -> bool:\n    return isinstance(client, (AsyncRedis, SyncRedis, AsyncRedisCluster, SyncRedisCluster))","tryCatchPattern":"try:\n    await client.initialize()\nexcept TypeError as e:\n    if \"Unsupported client type\" in str(e):\n        # swap the offending DatabaseConfig to use redis.asyncio.Redis / RedisCluster\n        raise RuntimeError(\"use redis.asyncio.Redis or RedisCluster as the database client\")\n    raise","preventionTips":["Use redis.asyncio.Redis or redis.asyncio.RedisCluster as the database client only.","Make any custom client subclass one of the four supported bases so isinstance passes.","In tests, use a real AsyncRedis or a fakeredis that subclasses AsyncRedis, not an unrelated Mock.","Inspect the message's type(...) to find the offending database."],"tags":["multidb","health-check","typeerror","config","validation"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}