From dd851c03f62003905601adeb678d1cf4b43f8bac Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Tue, 19 May 2026 11:19:41 -0400 Subject: [PATCH] fix data race in error logs for replication We have a few places in replication where we log error messages that reference a peer from a `followerReplication`. We aren't taking a read lock here, so there's a data race if the address for a peer changes. Take the read lock around these logs. Fixes: https://github.com/hashicorp/raft/issues/681 --- replication.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/replication.go b/replication.go index d48a8c83..eec8fb74 100644 --- a/replication.go +++ b/replication.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2013, 2025 +// Copyright IBM Corp. 2013, 2026 // SPDX-License-Identifier: MPL-2.0 package raft @@ -10,7 +10,7 @@ import ( "sync/atomic" "time" - "github.com/hashicorp/go-metrics/compat" + metrics "github.com/hashicorp/go-metrics/compat" ) const ( @@ -518,7 +518,10 @@ func (r *Raft) pipelineSend(s *followerReplication, p AppendPipeline, nextIdx *u // Pipeline the append entries if _, err := p.AppendEntries(req, new(AppendEntriesResponse)); err != nil { - r.logger.Error("failed to pipeline appendEntries", "peer", s.peer, "error", err) + s.peerLock.RLock() + peer := s.peer + s.peerLock.RUnlock() + r.logger.Error("failed to pipeline appendEntries", "peer", peer, "error", err) return true } @@ -644,7 +647,11 @@ func appendStats(peer string, start time.Time, logs float32, skipLegacy bool) { // handleStaleTerm is used when a follower indicates that we have a stale term. func (r *Raft) handleStaleTerm(s *followerReplication) { - r.logger.Error("peer has newer term, stopping replication", "peer", s.peer) + s.peerLock.RLock() + peer := s.peer + s.peerLock.RUnlock() + + r.logger.Error("peer has newer term, stopping replication", "peer", peer) s.notifyAll(false) // No longer leader asyncNotifyCh(s.stepDown) }