redis/redis-rb · error · Redis::Distributed::CannotDistribute

WATCH cannot be used in Redis::Distributed because the keys

Error message

WATCH cannot be used in Redis::Distributed because the keys involved need to be on the same server or because we cannot guarantee that the operation will be atomic.

What it means

Error "WATCH cannot be used in Redis::Distributed because the keys involved need to be on the same server or because we cannot guarantee that the operation will be atomic." thrown in redis/redis-rb.

Source

Thrown at lib/redis/distributed.rb:36

    attr_reader :ring

    def initialize(node_configs, options = {})
      @tag = options[:tag] || /^\{(.+?)\}/
      @ring = options[:ring] || HashRing.new
      @node_configs = node_configs.map(&:dup)
      @default_options = options.dup
      # Schemas registered via himport_prepare, replayed to nodes that join the ring later (see
      # #add_node) so ring membership changes don't leave nodes without the fieldsets that
      # key-routed himport_set calls expect. Initialized before the add_node loop below.
      @himport_fieldsets = {}
      node_configs.each { |node_config| add_node(node_config) }
      @subscribed_node = nil
      @watch_key = nil
    end

    def node_for(key)
      key = key_tag(key.to_s) || key.to_s
      raise CannotDistribute, :watch if @watch_key && @watch_key != key

      @ring.get_node(key)
    end

    def nodes
      @ring.nodes
    end

    def add_node(options)
      options = { url: options } if options.is_a?(String)
      options = @default_options.merge(options)
      options.delete(:tag)
      options.delete(:ring)
      node = Redis.new(options)
      # Replay registered fieldsets before the node can receive key-routed himport_set calls:
      # a node joining after a himport_prepare fan-out has neither the server-side fieldset nor
      # a populated registry to self-recover from "no such fieldset".
      @himport_fieldsets.each { |name, fields| node.himport_prepare(name, fields) }

View on GitHub (pinned to 2ba9010b91)

Solutions

  1. Do not use watch/multi optimistic locking on Redis::Distributed; run the WATCH-based transaction against a single Redis instance that holds all involved keys.
  2. Use Redis::Cluster or a standalone Redis connection if you need WATCH semantics.

When it happens

Trigger: Thrown at lib/redis/distributed.rb:36 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of redis/redis-rb@2ba9010b91 (2026-08-23). Data as JSON: /api/errors/24ed7165b257be24. Report an issue: GitHub.