redis/redis-py · error · ValueError

Either maint_notifications_pool_handler or oss_cluster_maint

Error message

Either maint_notifications_pool_handler or oss_cluster_maint_notifications_handler must be set

What it means

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.

Source

Thrown at redis/asyncio/connection.py:2199

        """Update the maintenance notifications config for all connections in the pool."""
        async with self._get_pool_lock():
            for conn in list(self._get_free_connections()):
                if oss_cluster_maint_notifications_handler:
                    conn.set_maint_notifications_cluster_handler_for_connection(
                        oss_cluster_maint_notifications_handler
                    )
                    conn.maint_notifications_config = (
                        oss_cluster_maint_notifications_handler.config
                    )
                elif maint_notifications_pool_handler:
                    conn.set_maint_notifications_pool_handler_for_connection(
                        maint_notifications_pool_handler
                    )
                    conn.maint_notifications_config = (
                        maint_notifications_pool_handler.config
                    )
                else:
                    raise ValueError(
                        "Either maint_notifications_pool_handler or "
                        "oss_cluster_maint_notifications_handler must be set"
                    )
                await conn.disconnect()

            for conn in list(self._get_in_use_connections()):
                if oss_cluster_maint_notifications_handler:
                    # Use set_maint_notifications_cluster_handler_for_connection
                    # (not _configure_maintenance_notifications) so the parser is
                    # obtained from the connection itself. _configure_* requires a
                    # parser argument and would raise here; it would also reset the
                    # connection's orig_* settings, which is wrong for an in-use
                    # (active) connection. This mirrors the idle-connection branch
                    # above and the pool-handler branches.
                    conn.set_maint_notifications_cluster_handler_for_connection(
                        oss_cluster_maint_notifications_handler
                    )
                    conn.maint_notifications_config = (

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. 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.
  2. If you must call it, pass exactly one of maint_notifications_pool_handler or oss_cluster_maint_notifications_handler.
  3. Audit your subclass to ensure it forwards both arguments from the public path.

Example fix

// before
await pool._update_maint_notifications_configs_for_connections(
    maint_notifications_pool_handler=None,
    oss_cluster_maint_notifications_handler=None,
)
// after
await pool.update_maint_notifications_config(
    MaintNotificationsConfig(enabled=True)
)
Defensive patterns

Strategy: validation

Validate before calling

def handlers_present(pool_handler, oss_handler) -> bool:
    return bool(pool_handler) or bool(oss_handler)

# before calling the private updater:
assert handlers_present(pool_handler, oss_handler)

Type guard

def exactly_one_handler_set(pool_handler, oss_handler) -> bool:
    return bool(pool_handler) ^ bool(oss_handler)

Try / catch

try:
    await pool._update_maint_notifications_configs_for_connections(
        maint_notifications_pool_handler=h, oss_cluster_maint_notifications_handler=None)
except ValueError as e:
    if 'must be set' in str(e):
        # route through the public update API instead
        ...

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/2a0dadff76f9fa39.json. Report an issue: GitHub.