Consul Ops Pro study materials
Consul Ops Pro study resources

Stale bootstrap_expect plus empty data directories: no cluster leader

Consul Ops Pro · Put your knowledge to work in context.

All case studies

Stale bootstrap_expect plus empty data directories: no cluster leader

Northwind's production cluster began as five Consul servers with bootstrap_expect = 5 hard-coded in a static configuration file. Two servers were decommissioned six months ago using consul leave and consul operator raft remove-peer, leaving three voters, but nobody edited the configuration. Last weekend a log rotation bug filled /var/consul on all three survivors and corrupted the Raft state. Rather than recover in place, the SRE team replaced all three instances from the golden image, so each started with an empty data directory, and started them within four minutes of each other. All three now log [WARN] raft: no known peers, aborting election and [ERR] agent: failed to sync remote state: No cluster leader in a loop. consul members shows all three servers alive and consul operator raft list-peers returns "No cluster leader". Nightly snapshots have run successfully for 90 days; the newest one in S3 is 14 hours old. The on-call engineer wants to start one server with -bootstrap to force an election and then rejoin the other two.

1. The servers report alive in `consul members` yet no leader exists. Explain precisely which subsystem each signal comes from and the root cause of the missing leader.

Read the worked answer

consul members reports Serf LAN membership, a gossip layer entirely separate from Raft. All three agents can gossip, so all three show alive regardless of Raft health.

Raft needs a persisted configuration or an initial bootstrap. Because the instances were rebuilt with empty data directories, there is no on-disk Raft configuration. In that state a server self-bootstraps only when it observes bootstrap_expect peers. All three configs say 5, only 3 exist, so every server waits for two servers that will never appear and none creates an initial configuration. The log line raft: no known peers, aborting election is the fingerprint of an empty Raft configuration, not of quorum loss (which produces repeated election timeouts with known peers).

So the root cause is compound: loss of Raft state + a bootstrap_expect value that no longer matches the real voter count. Either condition alone would not have produced this outage.

2. Compare the two recovery paths and recommend one with a concrete procedure.

Read the worked answer

Path A: relabel and restart (fresh cluster). Set bootstrap_expect = 3 on all three servers and restart. This forms a new empty cluster: all KV data, intentions, ACL policies and tokens, and service registrations disappear. With ACLs enabled, a fresh cluster with no seeded management token is also unusable until you supply acl.tokens.initial_management or re-bootstrap ACLs. Acceptable only if the snapshot is untrustworthy.

Path B: restore the 14-hour-old snapshot (recommended).

  1. Stop all Consul agents.
  2. Start one server alone with bootstrap_expect = 1 (or -bootstrap-expect=1); wipe its data directory first if it holds partial state.
  3. Wait for a leader, then run consul snapshot restore backup.snap with a management token that exists in the snapshot.
  4. Verify consul operator raft list-peers shows one voter and consul kv get returns expected keys.
  5. Start the other two servers with bootstrap_expect = 3; they join and receive the restored state. Revert the temporary bootstrap_expect = 1 and restart the first server one last time.
  6. Confirm three voters, one leader, autopilot healthy, ACL token list populated, and that client agents have re-registered services.

Data loss is limited to roughly 14 hours of KV writes and catalog changes; agent anti-entropy re-publishes registrations automatically. Never leave -bootstrap in a production config: with persistent state an accidental -bootstrap can create an isolated single-node cluster.

3. What would you change so a future rebuild cannot silently reintroduce this failure?

Read the worked answer
  • Derive bootstrap_expect from inventory, not a static literal. Render it from the same source that defines server count, and add a pre-flight assertion in the DR runbook that consul operator raft list-peers voter count equals bootstrap_expect.
  • Alert on the actual failure mode. Page on consul.raft.state.leader == 0 sustained, on raft: no known peers log matches, and on disk usage of the data directory (the original trigger).
  • Protect the data directory. Move /var/consul to a dedicated volume with log rotation capped, and alert at 80% utilization rather than discovering corruption.
  • Keep snapshots externally and verify them. Store in S3 with retention, run consul snapshot inspect on each new file, and rehearse a restore quarterly into a scratch environment.
  • Use Autopilot intentionally. With cleanup_dead_servers and server_stabilization_time configured, dead voters are removed automatically, so the voter count and bootstrap_expect do not drift apart silently.