nats-io/nats-server · error · JSClusterNoPeersError
10005
10005
Error message
preferred server %q is already leader
What it means
JetStream cluster placement error (JSClusterNoPeersError, code 10005). When a stream/mirror/copy placement specifies a Preferred server, the server checks whether that peer is already the RAFT group leader. If the preferred server is already leader, it cannot be re-elected as a new leader via this operation, so the request fails.
Source
Thrown at server/jetstream_api.go:3365
// should check for return API errors and return those to the requestor if needed.
func (s *Server) getStepDownPreferredPlacement(group RaftNode, placement *Placement) (string, *ApiError) {
if placement == nil {
return _EMPTY_, nil
}
var preferredLeader string
if placement.Preferred != _EMPTY_ {
for _, p := range group.Peers() {
si, ok := s.nodeToInfo.Load(p.ID)
if !ok || si == nil {
continue
}
if si.(nodeInfo).name == placement.Preferred {
preferredLeader = p.ID
break
}
}
if preferredLeader == group.ID() {
return _EMPTY_, NewJSClusterNoPeersError(fmt.Errorf("preferred server %q is already leader", placement.Preferred))
}
if preferredLeader == _EMPTY_ {
return _EMPTY_, NewJSClusterNoPeersError(fmt.Errorf("preferred server %q not known", placement.Preferred))
}
} else {
possiblePeers := make(map[*Peer]nodeInfo, len(group.Peers()))
ourID := group.ID()
for _, p := range group.Peers() {
if p == nil {
continue // ... shouldn't happen.
}
si, ok := s.nodeToInfo.Load(p.ID)
if !ok || si == nil {
continue
}
ni := si.(nodeInfo)
if ni.offline || p.ID == ourID {
continueView on GitHub (pinned to 3a66a489d2)
Solutions
- Check the current leader first; skip the stepdown if the preferred server already leads
- Issue the stepdown without the Preferred field to let the cluster choose a new leader
- Make automation idempotent: treat this error as success (desired state already achieved)
Example fix
// before jsm stream leader stepdown STREAM --preferred-server=nats-3 // after LEADER=$(jsm stream info STREAM -j | jq -r .cluster.leader) [ "$LEADER" = "nats-3" ] || jsm stream leader stepdown STREAM --preferred-server=nats-3
Defensive patterns
Strategy: validation
Validate before calling
leader := getStreamLeader(streamName)
if leader == preferredServer {
return // already desired state, skip stepdown
} Type guard
func stepdownNeeded(currentLeader, preferred string) bool { return currentLeader != preferred } Try / catch
err := stepdown(stream, preferred)
var apiErr *jsm.APIError
if errors.As(err, &apiErr) && strings.Contains(apiErr.Description, "is already leader") {
// treat as success: preferred server already leads
} Prevention
- Read the stream's cluster.leader before issuing stepdown
- Make maintenance automation idempotent against this error
When it happens
Trigger: Issuing a leader-stepdown or stream re-placement API request (e.g. jsm stream leader stepdown --preferred-server=X, or the JS API leader stepdown endpoint) where server X is already the current leader of the group.
Common situations: Automation/scheduler scripts that run stepdown with a preferred target without first checking the current leader; re-running a failed maintenance job after the preferred server already became leader.
Related errors
- stream assignment or group missing
- group node missing
- cluster node skew detected
- consumer assignment or group missing
- 10062
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/da5868263f4def93.
Report an issue: GitHub.