{"record":{"id":"b15e04ec63b67287","repo":"tailscale/tailscale","slug":"marking-ancestor-intersection-w","errorCode":null,"errorMessage":"marking ancestor intersection: %w","messagePattern":"marking ancestor intersection: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tka/tailchonk.go","lineNumber":1034,"sourceCode":"\tif err != nil {\n\t\treturn AUMHash{}, fmt.Errorf(\"AllAUMs: %w\", err)\n\t}\n\tverdict := make(map[AUMHash]retainState, len(all))\n\tfor _, h := range all {\n\t\tverdict[h] = 0\n\t}\n\n\tif err := markYoungAUMs(storage, verdict, opts.MinAge); err != nil {\n\t\treturn AUMHash{}, fmt.Errorf(\"marking young AUMs: %w\", err)\n\t}\n\tif lastActiveAncestor, err = markActiveChain(storage, verdict, opts.MinChain, head); err != nil {\n\t\treturn AUMHash{}, fmt.Errorf(\"marking active chain: %w\", err)\n\t}\n\tif err := markDescendantAUMs(storage, verdict); err != nil {\n\t\treturn AUMHash{}, fmt.Errorf(\"marking descendant AUMs: %w\", err)\n\t}\n\tif lastActiveAncestor, err = markAncestorIntersectionAUMs(storage, verdict, lastActiveAncestor); err != nil {\n\t\treturn AUMHash{}, fmt.Errorf(\"marking ancestor intersection: %w\", err)\n\t}\n\n\ttoDelete := make([]AUMHash, 0, len(verdict))\n\tfor h, v := range verdict {\n\t\tif v&retainAUMMask == 0 { // no retention set\n\t\t\ttoDelete = append(toDelete, h)\n\t\t}\n\t}\n\n\tif err := storage.SetLastActiveAncestor(lastActiveAncestor); err != nil {\n\t\treturn AUMHash{}, err\n\t}\n\treturn lastActiveAncestor, storage.PurgeAUMs(toDelete)\n}\n","sourceCodeStart":1016,"sourceCodeEnd":1049,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/tka/tailchonk.go#L1016-L1049","documentation":"Wraps markAncestorIntersectionAUMs: after retention marking, compaction walks each retained AUM's ancestry to guarantee every retained chain reaches the candidate compaction ancestor, moving the candidate earlier when branches rejoin the active chain above it. This error therefore covers the ancestor-read failures ('reading X'), the child-walk failure ('reading children X'), and the integrity error 'reached genesis AUM without intersecting with candidate ancestor' from that phase. Compaction aborts before anything is deleted, so the chonk stays consistent — only larger.","triggerScenarios":"Retained AUMs whose ancestry contains missing (purged or never-synced) or corrupt AUMs; forks that intersect the active chain before the candidate ancestor while their history is incomplete; concurrent writers racing the walk.","commonSituations":"Compacting a node whose fork sync never completed all history; earlier manual deletion of 'old' files that were still referenced by retained branches.","solutions":["Read the inner error: 'reading X' means ancestor X is missing or corrupt — fetch it from a peer or quarantine the dangling branch; 'reached genesis' means a retained chain never intersects the candidate — complete the resync before compacting","Verify every retained AUM can walk to a stored ancestor (parents all present in AllAUMs) before retrying Compact","Safe fallback: skip compaction this cycle — nothing is deleted and storage keeps growing until the chain is repairable"],"exampleFix":"// before\nif _, err := tka.Compact(chonk, head, opts); err != nil {\n\treturn err // marking ancestor intersection: reading 3f9a..: ...\n}\n\n// after: compaction is best-effort housekeeping\nif _, err := tka.Compact(chonk, head, opts); err != nil {\n\tlog.Printf(\"tka compaction deferred: %v\", err)\n}","handlingStrategy":"fallback","validationCode":"all, err := storage.AllAUMs()\nif err != nil { return err }\nhave := make(map[tka.AUMHash]bool, len(all))\nfor _, h := range all { have[h] = true }\nfor _, h := range all {\n\ta, err := storage.AUM(h)\n\tif err != nil { continue }\n\tif p, ok := a.Parent(); ok && !have[p] {\n\t\treturn fmt.Errorf(\"AUM %v references missing parent %v; complete sync before compaction\", h, p)\n\t}\n}","typeGuard":null,"tryCatchPattern":"if _, err := tka.Compact(storage, head, opts); err != nil {\n\t// ancestor-intersection walk failed: skip compaction entirely this cycle;\n\t// nothing was deleted, storage stays consistent (just larger). Retry after repair/resync.\n\tlog.Printf(\"tka compaction deferred: %v\", err)\n}","preventionTips":["Treat compaction as optional housekeeping — never propagate its failure fatally","Complete syncs (all parents present) before compacting","Monitor chonk size so deferred compaction is visible"],"tags":["tailscale","tka","compaction","chain-integrity","go"],"backgroundTag":"chain-traversal-failed","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"}