phacility/phabricator · warning · PhabricatorWorkerPermanentFailureException

Commit "%s" (with PHID "%s") is no longer reachable from any

Error message

Commit "%s" (with PHID "%s") is no longer reachable from any branch, tag, or ref in this repository, so it will not be imported. This usually means that the branch the commit was on was deleted or overwritten.

What it means

loadCommit() checks $commit->isUnreachable() after loading the commit (PhabricatorRepositoryCommitParserWorker.php:50-60). The row exists but is no longer reachable from any branch, tag, or ref; Phabricator deliberately refuses to spend parse effort on unreachable commits and permanently fails the task. This almost always means the branch the commit lived on was deleted or force-pushed away between discovery and parsing.

Source

Thrown at src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php:51

        }
      }
    }

    if (!$commit_phid) {
      throw new PhabricatorWorkerPermanentFailureException(
        pht('Task data has no "commitPHID".'));
    }

    $commit = id(clone $commit_query)
      ->withPHIDs(array($commit_phid))
      ->executeOne();
    if (!$commit) {
      throw new PhabricatorWorkerPermanentFailureException(
        pht('Commit "%s" does not exist.', $commit_phid));
    }

    if ($commit->isUnreachable()) {
      throw new PhabricatorWorkerPermanentFailureException(
        pht(
          'Commit "%s" (with PHID "%s") is no longer reachable from any '.
          'branch, tag, or ref in this repository, so it will not be '.
          'imported. This usually means that the branch the commit was on '.
          'was deleted or overwritten.',
          $commit->getMonogram(),
          $commit_phid));
    }

    $this->commit = $commit;

    return $commit;
  }

  final protected function doWork() {
    $commit = $this->loadCommit();
    $repository = $commit->getRepository();

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Usually this is correct behavior - let the task permanently fail, since the commit is garbage in the current repository state
  2. If the commit still matters, restore reachability (push the branch back or revert the force-push), then run bin/repository discover and bin/repository reparse --message --change <commit>
  3. Reduce parse queue lag (more daemon workers) so commits are parsed before their branches are deleted
Defensive patterns

Strategy: validation

Validate before calling

// Check reachability before spending effort on a commit.
if ($commit->isUnreachable()) {
  // skip; the commit is orphaned by a deleted/rewritten branch
}

Type guard

function isParseableCommit(PhabricatorRepositoryCommit $commit) {
  return !$commit->isUnreachable();
}

Try / catch

try {
  $commit = $worker->loadCommit();
} catch (PhabricatorWorkerPermanentFailureException $ex) {
  // Unreachable commit is expected churn in repos with branch deletion;
  // log at info level and let the task expire. If the commit matters,
  // restore the branch, re-discover, and reparse instead of retrying.
  phlog(pht('Skipping unreachable commit: %s', $ex->getMessage()));
}

Prevention

When it happens

Trigger: Force-push rewrites or branch deletion after the commit was discovered but before its parse task ran; quickly-deleted feature branches in busy mirrors; any ref removal that orphans a discovered commit.

Common situations: GitHub mirrors where PR branches are deleted immediately after merge; repositories with force-push policies; parse queue lag long enough for branches to disappear first.

Related errors


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