{"record":{"id":"ad8480d89e55fd50","repo":"phacility/phabricator","slug":"commit-s-is-not-a-reachable-ancestor-of-s","errorCode":null,"errorMessage":"Commit \"%s\" is not a reachable ancestor of \"%s\".","messagePattern":"Commit \"(.+?)\" is not a reachable ancestor of \"(.+?)\"\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/repository/daemon/PhabricatorGitGraphStream.php","lineNumber":88,"sourceCode":"      list($hash, $parents, $epoch) = explode(\"\\1\", $line);\n\n      if ($parents) {\n        $parents = explode(' ', $parents);\n      } else {\n        // First commit.\n        $parents = array();\n      }\n\n      $this->dates[$hash] = $epoch;\n      $this->parents[$hash] = $parents;\n\n      if ($this->isParsed($commit)) {\n        return;\n      }\n    }\n\n    if ($this->startCommit !== null) {\n      throw new Exception(\n        pht(\n          'Commit \"%s\" is not a reachable ancestor of \"%s\".',\n          $commit,\n          $this->startCommit));\n    } else {\n      throw new Exception(\n        pht(\n          'Commit \"%s\" is not a reachable ancestor of any ref.',\n          $commit));\n    }\n  }\n\n  private function isParsed($commit) {\n    return isset($this->dates[$commit]);\n  }\n\n}\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/repository/daemon/PhabricatorGitGraphStream.php#L70-L106","documentation":"Exception from PhabricatorGitGraphStream: the stream finished parsing 'git log' output without ever reaching the requested commit, and the stream was started from a specific start commit. The requested commit is not reachable from the history the stream walked — the repository state does not match the expectation that the commit is an ancestor of the start commit.","triggerScenarios":"The graph stream (used by repository daemons to resolve commit dates/parents) is given a start commit and asked for a commit that git log never emits: the commit is on an unrelated branch, history was rewritten/force-pushed so the commit is no longer an ancestor, the mirror is a shallow clone, or the object is missing. Raised from the loop that fills dates/parents once log output is exhausted without isParsed() success.","commonSituations":"Force pushes or history rewrites in the upstream repository after Phabricator parsed older data; shallow/incomplete mirrors or interrupted pulls; querying a commit hash that exists in the object store but is dangling (not reachable from any ref walked); races where refs moved mid-parse.","solutions":["Verify the ancestry in the repository mirror: git merge-base --is-ancestor <commit> <start> ; a non-zero exit confirms the stream cannot ever find it.","Repair the mirror: re-pull from the primary, or re-clone if history was rewritten ( Phabricator repository hosting 'Destroy/Reclone' path), ensuring a full (non-shallow) clone.","If the commit is genuinely unrelated (different branch), correct the caller that assumed ancestry and pass the right start commit/ref.","Run git fsck on the mirror to detect missing/corrupt objects, and check daemon logs for interrupted pulls that left the mirror stale."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before asking the stream for a commit, verify ancestry in the mirror:\nlist($rc) = execx_remote(...); // conceptually:\n// git merge-base --is-ancestor <commit> <start-commit>\nif ($rc !== 0) { /* skip or re-pull before parsing */ }","typeGuard":"function isReachableAncestor($repository_path, $commit, $start) {\n  $future = new ExecFuture('git -C %s merge-base --is-ancestor %s %s',\n    $repository_path, $commit, $start);\n  list($err) = $future->resolve();\n  return $err === 0;\n}","tryCatchPattern":"try {\n  $date = $stream->getCommitDate($commit);\n} catch (Exception $ex) {\n  // log, re-pull/re-clone mirror, and re-queue the task\n  phlog($ex);\n  $this->yieldToDaemon(); // retry after repository repair\n}","preventionTips":["Keep mirrors full clones; avoid shallow clones on hosted repos.","Re-pull immediately after known force pushes upstream.","Verify commit reachability with git merge-base --is-ancestor before bulk graph queries."],"tags":["php","phabricator","git","repository-daemon","history-rewrite"],"backgroundTag":"unreachable-commit","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}