{"record":{"id":"320435ff460fb26f","repo":"tailscale/tailscale","slug":"computing-ancestor-v","errorCode":null,"errorMessage":"computing ancestor: %v","messagePattern":"computing ancestor: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tka/tka.go","lineNumber":398,"sourceCode":"//     formerly (in a previous run) part of the chain.\n//  3. Compute the state of the state machine at this ancestor. This is\n//     needed for fast-forward, as each update operates on the state of\n//     the update preceding it.\n//  4. Iteratively apply updates till we reach head ('fast forward').\nfunc computeActiveChain(storage Chonk, lastKnownOldest *AUMHash, maxIter int) (chain, error) {\n\tchains, err := computeChainCandidates(storage, lastKnownOldest, maxIter)\n\tif err != nil {\n\t\treturn chain{}, fmt.Errorf(\"computing candidates: %v\", err)\n\t}\n\n\tif len(chains) == 0 {\n\t\treturn chain{}, errors.New(\"no chain candidates in AUM storage\")\n\t}\n\n\t// Find the right ancestor.\n\toldestHash, err := computeActiveAncestor(chains)\n\tif err != nil {\n\t\treturn chain{}, fmt.Errorf(\"computing ancestor: %v\", err)\n\t}\n\tancestor, err := storage.AUM(oldestHash)\n\tif err != nil {\n\t\treturn chain{}, err\n\t}\n\n\t// At this stage we know the ancestor AUM, so we have excluded distinct\n\t// chains but we might still have forks (so we don't know the head AUM).\n\t//\n\t// We iterate forward from the ancestor AUM, handling any forks as we go\n\t// till we arrive at a head.\n\tout := chain{Oldest: ancestor, Head: ancestor}\n\tif out.state, err = computeStateAt(storage, maxIter, oldestHash); err != nil {\n\t\treturn chain{}, fmt.Errorf(\"bootstrapping state: %v\", err)\n\t}\n\tout.Head, out.state, err = fastForward(storage, maxIter, out.state, nil)\n\tif err != nil {\n\t\treturn chain{}, fmt.Errorf(\"fast forward: %v\", err)","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/tka/tka.go#L380-L416","documentation":"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.","triggerScenarios":"Thrown at tka/tka.go:398 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}