hashicorp/nomad · error

unsupported minimum common raft protocol version

Error message

unsupported minimum common raft protocol version

What it means

TransferLeadershipToPeer (operator raft transfer-leadership RPC) refuses to run when the cluster-wide minimum common Raft protocol version is below 3, since Raft protocol v3 is required for explicit leadership transfer. The server returns a 400 with this message after logging a warning with required vs current versions.

Source

Thrown at nomad/operator_endpoint.go:242

	// currently no leader.
	if reply.From.Address == "" || reply.From.ID == "" {
		reply.Err = structs.ErrNoLeader
		return structs.NewErrRPCCoded(http.StatusServiceUnavailable, structs.ErrNoLeader.Error())
	}

	// while this is a somewhat more expensive test than later ones, if this
	// test fails, they will _never_ be able to do a transfer. We do this after
	// ACL checks though, so as to not leak cluster info to non-validated users.
	minRaftProtocol, err := op.srv.MinRaftProtocol()
	if err != nil {
		reply.Err = err
		return structs.NewErrRPCCoded(http.StatusInternalServerError, err.Error())
	}

	// TransferLeadership is not supported until Raft protocol v3 or greater.
	if minRaftProtocol < 3 {
		op.logger.Warn("unsupported minimum common raft protocol version", "required", "3", "current", minRaftProtocol)
		reply.Err = errors.New("unsupported minimum common raft protocol version")
		return structs.NewErrRPCCoded(http.StatusBadRequest, reply.Err.Error())
	}

	var kind, testedVal string

	// The request must provide either an ID or an Address, this lets us validate
	// the request
	req.Validate()
	switch {
	case req.ID != "":
		kind, testedVal = "id", string(req.ID)
	case req.Address != "":
		kind, testedVal = "address", string(req.Address)
	default:
		reply.Err = errors.New("must provide peer id or address")
		return structs.NewErrRPCCoded(http.StatusBadRequest, reply.Err.Error())
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Upgrade all Nomad servers to a version using Raft protocol 3+ and remove any raft_protocol < 3 settings in server blocks
  2. Check `nomad operator raft list-peers` (or the agent members output) to find the peer still on an older protocol and upgrade/restart it
  3. As a workaround, let Raft transfer leadership naturally (stop the leader) instead of using explicit transfer

Example fix

// before
server {
  raft_protocol = 2
}
// after
server {
  raft_protocol = 3
}
Defensive patterns

Strategy: validation

Validate before calling

peers, _, _ := client.Operator().RaftPeers(nil)
for _, p := range peers {
    if p.RaftProtocol < 3 {
        return fmt.Errorf("peer %s on raft protocol %d; upgrade before transfer", p.ID, p.RaftProtocol)
    }
}

Try / catch

resp, err := client.Operator().RaftTransferLeadership(peerID, addr, nil)
if err != nil && strings.Contains(err.Error(), "unsupported minimum common raft protocol") {
    // upgrade the lagging server, then retry
}

Prevention

When it happens

Trigger: Running `nomad operator raft transfer-leadership -peer-id <id>` (or the equivalent HTTP POST to /v1/operator/raft/transfer-leadership) while any server in the cluster still speaks Raft protocol v2 or lower (Nomad < 0.8 servers present, or min_raft_protocol/raft_protocol lowered below 3 on a peer).

Common situations: Mixed-version clusters during rolling upgrades; operators manually setting raft_protocol = 2 in server config for legacy compatibility; newly added old-version servers dragging down min common protocol.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/b2020e3f03428a7f. Report an issue: GitHub.