phacility/phabricator · error · Exception

Commit "%s" is not a reachable ancestor of "%s".

Error message

Commit "%s" is not a reachable ancestor of "%s".

What it means

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.

Source

Thrown at src/applications/repository/daemon/PhabricatorGitGraphStream.php:88

      list($hash, $parents, $epoch) = explode("\1", $line);

      if ($parents) {
        $parents = explode(' ', $parents);
      } else {
        // First commit.
        $parents = array();
      }

      $this->dates[$hash] = $epoch;
      $this->parents[$hash] = $parents;

      if ($this->isParsed($commit)) {
        return;
      }
    }

    if ($this->startCommit !== null) {
      throw new Exception(
        pht(
          'Commit "%s" is not a reachable ancestor of "%s".',
          $commit,
          $this->startCommit));
    } else {
      throw new Exception(
        pht(
          'Commit "%s" is not a reachable ancestor of any ref.',
          $commit));
    }
  }

  private function isParsed($commit) {
    return isset($this->dates[$commit]);
  }

}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. 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.
  2. 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.
  3. If the commit is genuinely unrelated (different branch), correct the caller that assumed ancestry and pass the right start commit/ref.
  4. Run git fsck on the mirror to detect missing/corrupt objects, and check daemon logs for interrupted pulls that left the mirror stale.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before asking the stream for a commit, verify ancestry in the mirror:
list($rc) = execx_remote(...); // conceptually:
// git merge-base --is-ancestor <commit> <start-commit>
if ($rc !== 0) { /* skip or re-pull before parsing */ }

Type guard

function isReachableAncestor($repository_path, $commit, $start) {
  $future = new ExecFuture('git -C %s merge-base --is-ancestor %s %s',
    $repository_path, $commit, $start);
  list($err) = $future->resolve();
  return $err === 0;
}

Try / catch

try {
  $date = $stream->getCommitDate($commit);
} catch (Exception $ex) {
  // log, re-pull/re-clone mirror, and re-queue the task
  phlog($ex);
  $this->yieldToDaemon(); // retry after repository repair
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/ad8480d89e55fd50. Report an issue: GitHub.