phacility/phabricator · error · Exception

Diff ("%s") has wrong revision ID ("%s", expected "%s").

Error message

Diff ("%s") has wrong revision ID ("%s", expected "%s").

What it means

After loading the diff, the land operation verifies the diff actually belongs to the revision on the operation by comparing `$diff->getRevisionID()` with the revision's ID. A mismatch means the stored `differential.diffPHID` points at a diff attached to a different revision — merging would land someone else's changes under this revision's commit message. This is a data-integrity guard, so it throws rather than guessing.

Source

Thrown at src/applications/drydock/operation/DrydockLandRepositoryOperation.php:214

    $revision = $operation->getObject();

    $diff_phid = $operation->getProperty('differential.diffPHID');

    $diff = id(new DifferentialDiffQuery())
      ->setViewer($viewer)
      ->withPHIDs(array($diff_phid))
      ->executeOne();
    if (!$diff) {
      throw new Exception(
        pht(
          'Unable to load diff "%s".',
          $diff_phid));
    }

    $diff_revid = $diff->getRevisionID();
    $revision_id = $revision->getID();
    if ($diff_revid != $revision_id) {
      throw new Exception(
        pht(
          'Diff ("%s") has wrong revision ID ("%s", expected "%s").',
          $diff_phid,
          $diff_revid,
          $revision_id));
    }

    return $diff;
  }

  public function getBarrierToLanding(
    PhabricatorUser $viewer,
    DifferentialRevision $revision) {

    $repository = $revision->getRepository();
    if (!$repository) {
      return array(
        'title' => pht('No Repository'),

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Discard the stale operation (release it) and issue a fresh land request so diff PHID and revision are captured atomically
  2. Verify the pairing manually: load the diff and check its revisionID matches the operation's object
  3. If you maintain custom creation code, read the diff PHID from the same revision object you bind to the operation, at the same moment
  4. Do not hand-edit differential.diffPHID on existing operations

Example fix

// before
$diff = id(new DifferentialDiffQuery())
  ->setViewer($viewer)
  ->withPHIDs(array($stale_diff_phid))
  ->executeOne();
// Exception: Diff ("PHID-DIFF-x") has wrong revision ID ("101", expected "102").

// after
$diff_phid = $revision->getActiveDiff()->getPHID(); // captured from the bound revision
$diff = id(new DifferentialDiffQuery())
  ->setViewer($viewer)
  ->withPHIDs(array($diff_phid))
  ->executeOne();
Defensive patterns

Strategy: validation

Validate before calling

// Check diff/revision pairing before land executes:
$diff = id(new DifferentialDiffQuery())
  ->setViewer($viewer)
  ->withPHIDs(array($operation->getProperty('differential.diffPHID')))
  ->executeOne();
$revision = $operation->getObject();
if ($diff->getRevisionID() != $revision->getID()) {
  // stale pairing: rebuild the operation from the revision's active diff
}

Try / catch

catch (Exception $ex) { on 'has wrong revision ID', discard the stale operation (release it) rather than retrying; re-issue land so diff and revision are captured together }

Prevention

When it happens

Trigger: The revision is updated while a land operation is queued, and stale properties mix the new revision with an old diff; manual property edits pointing diffPHID at another revision's diff; code that copies operations/properties between revisions (e.g. revision-forking tooling).

Common situations: Race between 'Request Changes'/'Land' and the author updating the revision; diffs re-parented by database repair; multiple land attempts reusing an older operation row.

Related errors


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