{"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/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/asyncio/multidb/healthcheck.py#L195-L231","documentation":"Raised by `AbstractHealthCheckPolicy.get_client()` (redis/asyncio/multidb/healthcheck.py:213) when `database.client` is not one of the supported types (`AsyncRedis`, `SyncRedis`, `AsyncRedisCluster`, `SyncRedisCluster`). The health-check client builder only knows how to mirror connection kwargs for those four types; anything else (a custom wrapper, a mock, a Sentinel client) is rejected with TypeError.","triggerScenarios":"Passing a `DatabaseConfig` whose underlying client is a custom subclass or a non-Redis object (e.g. a test double/mock, a wrapped client, or a Sentinel-managed client) and triggering `get_client()` during a health check.","commonSituations":"Subclassing `redis.asyncio.Redis` in a way that breaks `isinstance`; injecting a mock client in tests; using a third-party Redis wrapper as the `client_class` in MultiDbConfig.","solutions":["Use one of the supported types directly — set `MultiDbConfig.client_class` to `Redis` or `RedisCluster` (sync or async variants as appropriate).","If subclassing, ensure your subclass still passes `isinstance(client, (AsyncRedis, SyncRedis, AsyncRedisCluster, SyncRedisCluster))`.","In tests, provide a real (or testcontainer-backed) Redis client rather than an unrelated mock as the database client."],"exampleFix":"# before\nclass MyRedis(redis.asyncio.Redis):\n    ...  # but constructed in a way isinstance fails, or a non-Redis wrapper\nclient = MultiDBClient(MultiDbConfig(\n    databases_config=[DatabaseConfig(client_kwargs={})],\n    client_class=MyRedis,  # if MyRedis is not a Redis subclass\n))\n\n# after\nclient = MultiDBClient(MultiDbConfig(\n    databases_config=[DatabaseConfig(from_url='redis://host:6379/0')],\n    client_class=redis.asyncio.Redis,\n))","handlingStrategy":"type-guard","validationCode":"import redis.asyncio as aioredis\nfrom redis.asyncio import RedisCluster as AsyncRedisCluster\nfrom redis.client import Redis as SyncRedis\nfrom redis.cluster import RedisCluster as SyncRedisCluster\n\ndef client_is_supported(database) -> bool:\n    return isinstance(database.client, (aioredis.Redis, SyncRedis, AsyncRedisCluster, SyncRedisCluster))","typeGuard":"import redis.asyncio as aioredis\nfrom redis.asyncio import RedisCluster as AsyncRedisCluster\nfrom redis.client import Redis as SyncRedis\nfrom redis.cluster import RedisCluster as SyncRedisCluster\n\ndef is_supported_client(database) -> bool:\n    return isinstance(database.client, (aioredis.Redis, SyncRedis, AsyncRedisCluster, SyncRedisCluster))","tryCatchPattern":"try:\n    await client.initialize()\nexcept TypeError as e:\n    if 'Unsupported client type' in str(e):\n        # switch client_class to Redis/RedisCluster in MultiDbConfig\n        ...\n    raise","preventionTips":["Use only `redis.asyncio.Redis` or `redis.asyncio.RedisCluster` (or sync twins) as the underlying client type.","If subclassing, preserve isinstance compatibility with one of the supported types.","In tests, inject real Redis clients (or testcontainers) rather than unrelated mocks as database.client."],"tags":["multidb","type","configuration","health"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}