{"record":{"id":"9e6fc691665bb804","repo":"redis/redis-rb","slug":"redis-the-server-does-not-support-resp3-the-hell","errorCode":null,"errorMessage":"Redis: the server does not support RESP3 (the HELLO 3 handshake failed); falling back to RESP2. Pass `protocol: 2` to select RESP2 explicitly and silence this warning.","messagePattern":"Redis: the server does not support RESP3 \\(the HELLO 3 handshake failed\\); falling back to RESP2\\. Pass `protocol: 2` to select RESP2 explicitly and silence this warning\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/redis.rb","lineNumber":291,"sourceCode":"  # cluster via Redis::Cluster::Client#handle_errors. Because every @client access — single commands,\n  # pipelined, multi, watch, and the pub/sub socket — flows through #synchronize, wrapping it here\n  # covers them all.\n  #\n  # Must be called while holding @monitor: it closes and replaces @client, so it has to be\n  # serialized with the command execution that uses @client. The retried block re-reads @client, so\n  # callers must reference the rebuilt instance (via the synchronize block argument), not a cached\n  # one.\n  def with_protocol_fallback\n    yield\n  rescue ::RedisClient::Error => error\n    if @options.fetch(:protocol, 3).to_i == 3 && Client.resp3_unsupported?(error)\n      @options = @options.merge(protocol: 2)\n      @client.close\n      @client = build_client\n      # Warn only once the RESP2 client is actually in place — if the rebuild itself raises we\n      # haven't really fallen back. Fires once per client: @options[:protocol] is now 2, so this\n      # branch never re-enters. Passing `protocol: 2` explicitly skips it (and silences this).\n      warn(\"Redis: the server does not support RESP3 (the HELLO 3 handshake failed); falling back \" \\\n           \"to RESP2. Pass `protocol: 2` to select RESP2 explicitly and silence this warning.\")\n      retry\n    end\n\n    raise\n  end\n\n  def _subscription(method, timeout, channels, block)\n    if block\n      if @subscription_client\n        raise SubscriptionError, \"This client is already subscribed\"\n      end\n\n      begin\n        # The pub/sub second socket is opened via @client.pubsub, which connects through\n        # ensure_connected rather than a command path. Route it through #synchronize so the same\n        # RESP3->RESP2 fallback applies when subscribe is the first operation against an old server.\n        @subscription_client = SubscribedClient.new(synchronize(&:pubsub))","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/redis/redis-rb/blob/2ba9010b91dab9e0fde1fbae3a9aae003f8bc307/lib/redis.rb#L273-L309","documentation":"Error \"Redis: the server does not support RESP3 (the HELLO 3 handshake failed); falling back to RESP2. Pass `protocol: 2` to select RESP2 explicitly and silence this warning.\" thrown in redis/redis-rb.","triggerScenarios":"Thrown at lib/redis.rb:291 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Pass protocol: 2 to Redis.new to select RESP2 explicitly and silence the fallback warning.","Upgrade the server to Redis 6.0 or newer to get native RESP3 support."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"2ba9010b91dab9e0fde1fbae3a9aae003f8bc307","analyzedAt":"2026-08-23T03:54:57.017Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}