Skip to content

Errors

What operators and apps actually see. This is a lookup page, not a substitute for the guide. Caps that are not bugs live in Limits.

Prefer clusdr members when you want to know if the Runtime API is up. clusdr status only checks that the Unix socket file exists.

Daemon and dial

You seeCauseWhat to do
daemon not running (socket not found: …)clusdr status: no control socket at that pathStart the daemon, or pass --config so the socket path matches. Prefer clusdr members
dial daemon at 127.0.0.1:7947: … / connection refusedNothing listening on the Runtime APIclusdr start is not running, or grpc.addr is another port. Point CLI --config at the same YAML
listen grpc runtime …: bind: address already in useAnother process owns that portSecond daemon needs its own grpc.addr, raft.addr, control_socket, and data.dir (grow)
config file "clusdr.yaml" already exists (use --force to overwrite)Second clusdr initKeep the existing identity. --force replaces config and prints a new join token
log node identity not found in store / hint run 'clusdr init'start without initThe process runs, but it is not a cluster. Run init, then start --bootstrap on the seed (first member)
Two daemons, shared data.dirBoltDB and certs are per processSeparate directories. Sharing a dir is undefined

clusdr status exit 1 when the socket is missing is intentional for scripts. It is not a readiness probe for Kubernetes unless you control that path (other hosts).

Join

Join talks to the local daemon (RequestJoin). That daemon then dials <addr> (the seed Runtime API).

You seeCauseWhat to do
UNAUTHORIZED / UNAUTHORIZED: invalid join tokenToken does not match the hash from initUse the plaintext printed once by clusdr init. Hash is stored; typing a new string will not work (security)
join rejected: cluster id mismatch: want "…"Both sides set cluster.id and they differLeave cluster.id empty on the joiner, or copy the seed’s id (grow)
join: … / Unavailable / dial leader …Seed down, wrong host:port, or no leader to forward to<addr> is Runtime (grpc.addr), not Raft. Wait until clusdr members on the seed shows a leader
this node has no CA key; join via a seed nodeYou asked a joiner (no CA private key) to issue certsJoin through a seed that ran init
Second process with --bootstrapNew Raft group, not a joinOnly the first voter uses --bootstrap. Joiners: clusdr start then clusdr join

Followers forward Join to the leader. NOT_LEADER after that means there is no leader (or the forward could not dial it).

TLS

TLS is on unless every node and client sets CLUSDR_TLS=disabled.

You seeCauseWhat to do
Certificate / handshake errors after joinOne side plaintext, the other mTLS; or different CAsSame tls.mode everywhere. Apps load ca.crt / node.crt / node.key from that host’s data.dir
Python: clusdr: TLS enabled but ca.crt/node.crt/node.key missing in …No PEMs in data_dir / CLUSDR_DATA_DIR / ~/.clusdrPoint data_dir at the daemon’s data dir, or CLUSDR_TLS=disabled / insecure=True (dev only). Python does not skip-verify like Go bootstrap TLS (Python SDK)
Python: clusdr: TLS hostname unknown; set CLUSDR_TLS_SERVER_NAME …No server_name, env, or CN on node.crtSet server_name= or CLUSDR_TLS_SERVER_NAME to the peer node id
Go SDK connects, Python does notGo falls back to bootstrap TLS when PEMs are missingGive Python the PEMs or disable TLS on both

clusdr certs show prints the CA fingerprint. Compare it across nodes. Server identity is the node id (SAN), not the dial hostname.

Cluster

You seeCauseWhat to do
clusdr leader / SDK UnavailableNo current leaderOne voter: that process must be up. Three voters: majority must be up (leadership)
Frequent elections, flapping leaderPeer RTT larger than Raft timersDefaults are 150ms heartbeat/election. Raise them (limits, configuration)
member.left while the process still existsPresence lease presence.<nodeID> expired (default 3s)Process wedged or partitioned. Heartbeats are the slower backup (presence)
Extra elections on Docker / two hostsnode.addr is 0.0.0.0 or 127.0.0.1 on a remote peerAdvertise a host:port peers can dial (other hosts)
Health.healthy is always trueNot a bugHealth.role is always standalone in this version. Use members

Locks and leases

You seeCauseWhat to do
FailedPrecondition / observer cannot mutate locksLock RPCs on an observer daemonTake locks on a voter (the leader writes the log). Or clusdr promote that node (observers)
fencing token mismatchUnlock/revoke with a stale tokenStore the token from the grant. A newer owner holds the name (locks, leases)
clusdr: lock "…" is not held by this client (same for lease)This process is not the holderAnother client owns it, or you already released. try_lock / TryLock returns not-held instead of blocking
too many locks / too many leases (max 4096)Table fullRelease unused names. Cap is limits
Name rejectedIllegal characters or length1–128 of A–Z a–z 0–9 . _ -

Observers can hold application leases. Presence still runs on observers so a dead observer leaves the member list.

Applications

SDK errors are wrapped (clusdr: daemon not ready at …, clusdr: lock "name": …). Unwrap to the gRPC status when you need the code.

You seeCauseWhat to do
clusdr: daemon not ready at …Dial ok-ish but Health not ready within ~10s, or daemon downStart the local daemon. The app never dials a remote member (from your app)
clusdr: empty dial addressDial("")Use Local() / local(), or pass CLUSDR_GRPC_ADDR
clusdr: publish rejected / payload too largeCustom event over 64 KiB or invalid typeShrink the payload. Publish is gossip, not Raft (events)
Watch reconnect misses custom.*Not a bugCustom events are ephemeral. Cluster events come back in the snapshot

Go: SDK errors. Python: SDK errors.

Documentation is sourced from the clusdr/docs tree.