nats-io/nats-server · error
raft: illegal peer: %q
Error message
raft: illegal peer: %q
What it means
When creating a raft group, NATS validates each peer in the knownPeers list has exactly idLen bytes. A peer ID of any other length means it is not a valid node ID, and the group creation fails with this quoted peer name in the error.
Source
Thrown at server/raft.go:396
errBadAppendEntry = errors.New("raft: append entry corrupt")
errNoInternalClient = errors.New("raft: no internal client")
errMembershipChange = errors.New("raft: membership change in progress")
errRemoveLastNode = errors.New("raft: cannot remove the last peer")
errPeerNotFound = errors.New("raft: peer not found")
errNotManaged = errors.New("raft: group membership is not managed")
errNotLeaderless = errors.New("raft: group is not leaderless")
errQuorumPossible = errors.New("raft: remaining peers could still reach quorum")
)
// This will bootstrap a raftNode by writing its config into the store directory.
func (s *Server) bootstrapRaftNode(cfg *RaftConfig, knownPeers []string, allPeersKnown bool) error {
if cfg == nil {
return errNilCfg
}
// Check validity of peers if presented.
for _, p := range knownPeers {
if len(p) != idLen {
return fmt.Errorf("raft: illegal peer: %q", p)
}
}
expected := len(knownPeers)
// We need to adjust this is all peers are not known.
if !allPeersKnown {
s.Debugf("Determining expected peer size for JetStream meta group")
if expected < 2 {
expected = 2
}
opts := s.getOpts()
nrs := len(opts.Routes)
cn := s.ClusterName()
ngwps := 0
for _, gw := range opts.Gateway.Gateways {
// Ignore our own cluster if specified.
if gw.Name == cn {
continueView on GitHub (pinned to 3a66a489d2)
Solutions
- Ensure every entry in knownPeers is a genuine server-generated node ID of idLen bytes.
- Remove or fix the offending peer reported in %q in the error message.
- Re-derive the peer list from the actual cluster membership instead of a hand-written list.
- Validate peer IDs (length check) before constructing the raft config.
Example fix
// before
knownPeers := []string{"node-a", "node-b"}
// after
knownPeers := clusterMembers() // real idLen-byte node IDs Defensive patterns
Strategy: validation
Validate before calling
// Validate all peer IDs before building the raft config
for _, p := range knownPeers {
if len(p) != idLen {
return fmt.Errorf("peer %q is not %d bytes", p, idLen)
}
} Type guard
func isValidPeerID(p string) bool {
return len(p) == idLen
} Try / catch
if _, err := createGroup(cfg, knownPeers, ...); err != nil {
return fmt.Errorf("rebuild peer list from cluster membership: %w", err)
} Prevention
- Derive knownPeers from actual cluster membership APIs.
- Never insert friendly names into raft peer lists.
- Sanitize peer state restored from snapshots/disk.
When it happens
Trigger: Calling the raft group creation path (stream/meta assignment) with a knownPeers slice containing a malformed/short/long peer ID.
Common situations: Passing human-readable or placeholder names instead of real raft node IDs, corrupted peer state restored from disk, or custom tooling building the peer list manually.
Related errors
- shutting down
- consumer write error: %v
- %w for stream '%s > %s'
- JS_CONSUMER_OFFLINE
- stream assignment or group missing
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/f04a1978c80e1a8a.
Report an issue: GitHub.