pika/pika · error · ValueError

timeout must >= 1, but got {timeout!r}

Error message

timeout must >= 1, but got {timeout!r}

What it means

HeartbeatChecker.__init__ (heartbeat.py:37-38) requires its timeout argument to be at least 1; anything smaller raises ValueError. The value drives both the heartbeat send interval (timeout/2) and the stale-connection check interval (timeout+5), so a zero or fractional timeout would produce a zero or negative send interval and break the scheduler. The check is a hard floor, not a recommendation.

Source

Thrown at pika/heartbeat.py:38

    _STALE_CONNECTION = 'No activity or too many missed heartbeats in the last %i seconds'

    def __init__(self, connection, timeout) -> None:
        """
        Create an object that will check for activity on the provided connection as well as receive
        heartbeat frames from the broker. The timeout parameter defines a window within which this
        activity must happen. If not, the connection is considered dead and closed.

        The value must be >= 1. The value passed for timeout is also used to calculate an interval
        at which a heartbeat frame is sent to the broker. The interval is equal to the timeout value
        divided by two.

        :param connection: Connection object
        :param timeout: Connection idle timeout. If no activity occurs on the connection nor
            heartbeat frames received during the timeout window the connection will be closed. The
            interval used to send heartbeats is calculated from this value by dividing it by two.
        """
        if timeout < 1:
            raise ValueError(f'timeout must >= 1, but got {timeout!r}')

        self._connection = connection

        # Note: see the following documents:
        # https://www.rabbitmq.com/heartbeats.html#heartbeats-timeout
        # https://github.com/pika/pika/pull/1072
        # https://groups.google.com/d/topic/rabbitmq-users/Fmfeqe5ocTY/discussion
        # There is a certain amount of confusion around how client developers
        # interpret the spec. The spec talks about 2 missed heartbeats as a
        # *timeout*, plus that any activity on the connection counts for a
        # heartbeat. This is to avoid edge cases and not to depend on network
        # latency.
        self._timeout = timeout

        self._send_interval = float(timeout) / 2

        # Note: Pika will calculate the heartbeat / connectivity check interval
        # by adding 5 seconds to the negotiated timeout to leave a bit of room

View on GitHub (pinned to 295ad9e579)

Solutions

  1. Ensure the heartbeat value passed is an integer >= 1 (use 0 only to disable, and let Connection._create_heartbeat_checker skip construction).
  2. If you need to disable heartbeats, set ConnectionParameters(heartbeat=0) rather than building a HeartbeatChecker manually.
  3. When using a heartbeat callback, clamp the return to max(1, desired) and return an int.

Example fix

# before
checker = pika.heartbeat.HeartbeatChecker(conn, 0)
# after
params = pika.ConnectionParameters(heartbeat=0)  # disables heartbeat entirely
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(params.heartbeat, int) and params.heartbeat < 1:
    # 0 disables; any other sub-1 int is invalid
    params.heartbeat = 0 if params.heartbeat == 0 else 1
# or, for a custom checker:
timeout = max(1, int(timeout)) if timeout else 0
if timeout:
    checker = pika.heartbeat.HeartbeatChecker(conn, timeout)

Type guard

def is_valid_heartbeat_timeout(v: int) -> bool:
    return isinstance(v, int) and v >= 1

Try / catch

try:
    checker = pika.heartbeat.HeartbeatChecker(conn, timeout)
except ValueError:
    timeout = 60
    checker = pika.heartbeat.HeartbeatChecker(conn, timeout)

Prevention

When it happens

Trigger: Negotiating a heartbeat of 0 with the broker would normally disable the checker (_create_heartbeat_checker guards with heartbeat > 0), but this error surfaces if HeartbeatChecker is constructed directly with a value < 1, or if a custom heartbeat callback returns 0 or a fractional value that bypasses the int/positivity guard at line 1671. Constructing pika.heartbeat.HeartbeatChecker(conn, 0) reproduces it.

Common situations: Directly instantiating HeartbeatChecker in tests or custom adapters with a 0 or negative timeout; a heartbeat negotiation callback returning a float < 1; manually setting params.heartbeat to a sub-1 value after tune.

Related errors


AI-assisted analysis of pika/pika@295ad9e579 (2026-08-04). Data as JSON: /data/errors/913b9b47a5ecd9de.json. Report an issue: GitHub.