{"id":"2a0dadff76f9fa39","repo":"redis/redis-py","slug":"either-maint-notifications-pool-handler-or-oss-clu","errorCode":null,"errorMessage":"Either maint_notifications_pool_handler or oss_cluster_maint_notifications_handler must be set","messagePattern":"Either maint_notifications_pool_handler or oss_cluster_maint_notifications_handler must be set","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/connection.py","lineNumber":2199,"sourceCode":"        \"\"\"Update the maintenance notifications config for all connections in the pool.\"\"\"\n        async with self._get_pool_lock():\n            for conn in list(self._get_free_connections()):\n                if oss_cluster_maint_notifications_handler:\n                    conn.set_maint_notifications_cluster_handler_for_connection(\n                        oss_cluster_maint_notifications_handler\n                    )\n                    conn.maint_notifications_config = (\n                        oss_cluster_maint_notifications_handler.config\n                    )\n                elif maint_notifications_pool_handler:\n                    conn.set_maint_notifications_pool_handler_for_connection(\n                        maint_notifications_pool_handler\n                    )\n                    conn.maint_notifications_config = (\n                        maint_notifications_pool_handler.config\n                    )\n                else:\n                    raise ValueError(\n                        \"Either maint_notifications_pool_handler or \"\n                        \"oss_cluster_maint_notifications_handler must be set\"\n                    )\n                await conn.disconnect()\n\n            for conn in list(self._get_in_use_connections()):\n                if oss_cluster_maint_notifications_handler:\n                    # Use set_maint_notifications_cluster_handler_for_connection\n                    # (not _configure_maintenance_notifications) so the parser is\n                    # obtained from the connection itself. _configure_* requires a\n                    # parser argument and would raise here; it would also reset the\n                    # connection's orig_* settings, which is wrong for an in-use\n                    # (active) connection. This mirrors the idle-connection branch\n                    # above and the pool-handler branches.\n                    conn.set_maint_notifications_cluster_handler_for_connection(\n                        oss_cluster_maint_notifications_handler\n                    )\n                    conn.maint_notifications_config = (","sourceCodeStart":2181,"sourceCodeEnd":2217,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/asyncio/connection.py#L2181-L2217","documentation":"Internal guard in _update_maint_notifications_configs_for_connections (free/idle connections branch). It requires that exactly one of maint_notifications_pool_handler or oss_cluster_maint_notifications_handler is set when iterating free connections; if both are None the pool cannot decide how to configure each connection. This indicates the caller passed neither handler, which should not happen via public API.","triggerScenarios":"Calling the private _update_maint_notifications_configs_for_connections() with both handler arguments set to None. Reachable only if a subclass or internal caller bypasses the public update_maint_notifications_config entry point and invokes the per-connection updater directly without a handler.","commonSituations":"Subclassing the pool and overriding/wrapping the maintenance update helpers incorrectly; library upgrades where an internal signature changed; direct calls into private methods during custom orchestration.","solutions":["Do not call the private _update_maint_notifications_configs_for_connections directly; use update_maint_notifications_config(config[, oss_cluster_handler]) which always supplies a handler.","If you must call it, pass exactly one of maint_notifications_pool_handler or oss_cluster_maint_notifications_handler.","Audit your subclass to ensure it forwards both arguments from the public path."],"exampleFix":"// before\nawait pool._update_maint_notifications_configs_for_connections(\n    maint_notifications_pool_handler=None,\n    oss_cluster_maint_notifications_handler=None,\n)\n// after\nawait pool.update_maint_notifications_config(\n    MaintNotificationsConfig(enabled=True)\n)","handlingStrategy":"validation","validationCode":"def handlers_present(pool_handler, oss_handler) -> bool:\n    return bool(pool_handler) or bool(oss_handler)\n\n# before calling the private updater:\nassert handlers_present(pool_handler, oss_handler)","typeGuard":"def exactly_one_handler_set(pool_handler, oss_handler) -> bool:\n    return bool(pool_handler) ^ bool(oss_handler)","tryCatchPattern":"try:\n    await pool._update_maint_notifications_configs_for_connections(\n        maint_notifications_pool_handler=h, oss_cluster_maint_notifications_handler=None)\nexcept ValueError as e:\n    if 'must be set' in str(e):\n        # route through the public update API instead\n        ...","preventionTips":["Do not call private _update_*_for_connections directly; use update_maint_notifications_config.","Always pass exactly one handler when calling internal update helpers.","Audit subclasses that wrap maintenance updates."],"tags":["maintenance-notifications","internal","pool","asyncio"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}