tailscale/tailscale · error
computing ancestor: %v
Error message
computing ancestor: %v
What it means
Wraps a failure of computeActiveAncestor, which selects the oldest surviving ancestor shared by the candidate chains. It fires when no single ancestor can be determined — e.g. the candidate chains are entirely distinct or the selection logic hit an internal storage error — so the active chain cannot be pinned to a starting point.
Source
Thrown at tka/tka.go:398
// formerly (in a previous run) part of the chain.
// 3. Compute the state of the state machine at this ancestor. This is
// needed for fast-forward, as each update operates on the state of
// the update preceding it.
// 4. Iteratively apply updates till we reach head ('fast forward').
func computeActiveChain(storage Chonk, lastKnownOldest *AUMHash, maxIter int) (chain, error) {
chains, err := computeChainCandidates(storage, lastKnownOldest, maxIter)
if err != nil {
return chain{}, fmt.Errorf("computing candidates: %v", err)
}
if len(chains) == 0 {
return chain{}, errors.New("no chain candidates in AUM storage")
}
// Find the right ancestor.
oldestHash, err := computeActiveAncestor(chains)
if err != nil {
return chain{}, fmt.Errorf("computing ancestor: %v", err)
}
ancestor, err := storage.AUM(oldestHash)
if err != nil {
return chain{}, err
}
// At this stage we know the ancestor AUM, so we have excluded distinct
// chains but we might still have forks (so we don't know the head AUM).
//
// We iterate forward from the ancestor AUM, handling any forks as we go
// till we arrive at a head.
out := chain{Oldest: ancestor, Head: ancestor}
if out.state, err = computeStateAt(storage, maxIter, oldestHash); err != nil {
return chain{}, fmt.Errorf("bootstrapping state: %v", err)
}
out.Head, out.state, err = fastForward(storage, maxIter, out.state, nil)
if err != nil {
return chain{}, fmt.Errorf("fast forward: %v", err)View on GitHub (pinned to 6e0912f979)
Solutions
- Examine the candidate chains: fully disjoint chains usually mean bad forks were stored; use MakeRetroactiveRevocation or resync to recover
- Ensure lastKnownOldest passed to computeActiveChain is consistent with stored history
- Resync from a healthy peer if local history has diverged irrecoverably
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at tka/tka.go:398 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18).
Data as JSON: /api/errors/320435ff460fb26f.
Report an issue: GitHub.