juanfont/headscale · error · ErrNodeKeyInUse
node key already in use by another machine
Error message
node key already in use by another machine
What it means
ErrNodeKeyInUse is a sentinel error in hscontrol/state/state.go:119 enforcing the invariant that a NodeKey binds 1:1 to one machine. It is returned at state.go:1744, 1911 and 2602 when a registration or re-auth presents a NodeKey already bound to a different machine (different MachineKey). Covered by auth_nodekey_binding_test.go and persist_test.go; API layers translate it to a machine-key-conflict response (v1/errors.go:42).
Source
Thrown at hscontrol/state/state.go:119
"IPv6",
"Hostname",
"GivenName",
"UserID",
"RegisterMethod",
"Tags",
"Expiry",
"LastSeen",
"ApprovedRoutes",
"UpdatedAt",
}
// ErrRegistrationExpired is returned when a registration has expired.
var ErrRegistrationExpired = errors.New("registration expired")
// ErrNodeKeyInUse is returned when a registration or re-auth claims a NodeKey
// already bound to a different machine, enforcing the 1:1 NodeKey<->MachineKey
// binding.
var ErrNodeKeyInUse = errors.New("node key already in use by another machine")
// ErrAmbiguousNodeOwnership is returned when a machine key maps to a set of
// nodes from which the correct one to update or convert cannot be determined:
// multiple user-owned candidates for a tagged conversion, or a tagged node and
// a user-owned node coexisting (impossible per validateNodeOwnership). The
// registration is rejected rather than mutating an arbitrarily-picked node.
var ErrAmbiguousNodeOwnership = errors.New("machine key maps to ambiguous node ownership")
// sshCheckPair identifies a (source, destination) node pair for
// SSH check auth tracking.
type sshCheckPair struct {
Src types.NodeID
Dst types.NodeID
}
// State manages Headscale's core state, coordinating between database, policy management,
// IP allocation, and DERP routing. All methods are thread-safe.
//View on GitHub (pinned to 565fd254d0)
Solutions
- Run 'tailscale logout' or delete the local state (/var/lib/tailscale) on the duplicate machine so it generates a fresh node key
- Alternatively delete the existing node (headscale node delete -i <id>) that holds the key, then re-register
- Never clone the tailscale state directory when imaging machines
- If the machine key intentionally changed (hardware swap), delete and re-register the node
Example fix
# before: cloned VM reuses node key, registration fails # after: on the clone, reset identity tailscale logout rm -rf /var/lib/tailscale/tailscaled.state systemctl restart tailscaled
Defensive patterns
Strategy: validation
Validate before calling
null
Type guard
null
Try / catch
if errors.Is(err, state.ErrNodeKeyInUse) {
// do not retry: delete the conflicting node or reset the client's tailscale state, then re-register
} Prevention
- Never clone the tailscale state directory when imaging machines
- On hardware/machine-key changes, delete the old node before re-registering
When it happens
Trigger: Registering a new machine with a NodeKey that an existing node already uses; re-authenticating after a machine-key change while keeping the old node key; restoring a node key backup onto different hardware with a new machine key.
Common situations: Cloning a VM/container including the tailscale state directory so both copies present the same node key; deliberately reusing a node key on new hardware; corrupted/mismatched state after disk imaging.
Related errors
- node name is not unique
- auth-key expired
- auth-key has already been used
- user mismatch
- failed to parse auth-key
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/b441feeee864beb6.
Report an issue: GitHub.