phacility/phabricator · error · Exception

Changeset ID "%s" is part of diff ID "%s", but that diff is

Error message

Changeset ID "%s" is part of diff ID "%s", but that diff is attached to revision "%s", not revision "%s".

What it means

Even when the revision and the changeset both exist, the controller verifies they belong together: the changeset's diff must be attached to the same revision. A mismatch throws this error. The check protects against stale parameter mixing and cross-revision request construction.

Source

Thrown at src/applications/differential/controller/DifferentialInlineCommentEditController.php:54

    $changeset_id = $this->getChangesetID();
    $viewer = $this->getViewer();

    $revision = $this->loadRevision();

    $changeset = id(new DifferentialChangesetQuery())
      ->setViewer($viewer)
      ->withIDs(array($changeset_id))
      ->executeOne();
    if (!$changeset) {
      throw new Exception(
        pht(
          'Invalid changeset ID "%s"!',
          $changeset_id));
    }

    $diff = $changeset->getDiff();
    if ($diff->getRevisionID() != $revision->getID()) {
      throw new Exception(
        pht(
          'Changeset ID "%s" is part of diff ID "%s", but that diff '.
          'is attached to revision "%s", not revision "%s".',
          $changeset_id,
          $diff->getID(),
          $diff->getRevisionID(),
          $revision->getID()));
    }

    return id(new DifferentialInlineComment())
      ->setRevision($revision)
      ->setChangesetID($changeset_id);
  }

  protected function loadCommentForDone($id) {
    $viewer = $this->getViewer();

    $inline = $this->loadCommentByID($id);

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Always derive both the revision id and the changeset id from the same revision/diff view.
  2. Re-render the comment form after the revision updates, so it embeds current IDs.
  3. In automation, fetch the changesets of the specific revision and use only those IDs.
Defensive patterns

Strategy: validation

Validate before calling

// before posting an inline comment, confirm the changeset id belongs to the
// revision being commented on
$changeset_ids = array(); // ids rendered with the current diff view
if (!in_array($changeset_id, $changeset_ids, true)) {
  throw new InvalidArgumentException(
    'Changeset does not belong to this revision.');
}

Try / catch

try {
  // submit the inline comment
} catch (Exception $ex) {
  if (preg_match('/is part of diff ID/', $ex->getMessage())) {
    // mixed ids: refresh both from the same revision view and resubmit
  } else {
    throw $ex;
  }
}

Prevention

When it happens

Trigger: Mixing a changeset id from revision A with the revision id of revision B in one inline-comment request — stale forms, request replay, or hand-built parameters.

Common situations: Two revisions open in parallel with a copy-pasted URL; automation that caches changeset IDs and reuses them across revisions.

Related errors


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