phacility/phabricator · error · ConduitException

ERR_BAD_REVISION

ERR_BAD_REVISION

Error message

ERR_BAD_REVISION

What it means

Thrown by the Conduit method differential.getrevision when the revision_id parameter does not resolve to a DifferentialRevision that the requesting user may see. The underlying query is policy-filtered, so a nonexistent ID and a policy-hidden revision produce the same error. It is the legacy read API's way of saying 'no such revision (that you can access)'.

Source

Thrown at src/applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php:50

  protected function defineErrorTypes() {
    return array(
      'ERR_BAD_REVISION' => pht('No such revision exists.'),
    );
  }

  protected function execute(ConduitAPIRequest $request) {
    $diff = null;

    $revision_id = $request->getValue('revision_id');
    $revision = id(new DifferentialRevisionQuery())
      ->withIDs(array($revision_id))
      ->setViewer($request->getUser())
      ->needReviewers(true)
      ->needCommitPHIDs(true)
      ->executeOne();

    if (!$revision) {
      throw new ConduitException('ERR_BAD_REVISION');
    }

    $reviewer_phids = $revision->getReviewerPHIDs();

    $diffs = id(new DifferentialDiffQuery())
      ->setViewer($request->getUser())
      ->withRevisionIDs(array($revision_id))
      ->needChangesets(true)
      ->execute();
    $diff_dicts = mpull($diffs, 'getDiffDict');

    $commit_dicts = array();
    $commit_phids = $revision->getCommitPHIDs();
    $handles = id(new PhabricatorHandleQuery())
      ->setViewer($request->getUser())
      ->withPHIDs($commit_phids)
      ->execute();

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Pass the numeric ID without the 'D' prefix: send 123, not 'D123'.
  2. Pre-check with differential.revision.search using constraints {"ids":[123]}; an empty result means the ID is wrong or invisible to this user.
  3. Verify the conduit user can see the revision (object view policy, project membership).
  4. Confirm you are talking to the instance the revision lives on.

Example fix

// before
$params = array('revision_id' => 'D123');
$client->callMethodSynchronous('differential.getrevision', $params);

// after
$params = array('revision_id' => 123);
$client->callMethodSynchronous('differential.getrevision', $params);
Defensive patterns

Strategy: validation

Validate before calling

$response = $client->callMethodSynchronous('differential.revision.search', array(
  'constraints' => array('ids' => array($revision_id)),
));
if (empty($response['data'])) {
  throw new InvalidArgumentException(
    'Revision '.$revision_id.' does not exist or is not visible.');
}

Type guard

function isRevisionID($value) {
  return is_int($value) && $value > 0;
}

Try / catch

try {
  $info = $client->callMethodSynchronous('differential.getrevision', $params);
} catch (ConduitClientException $ex) {
  if ($ex->getErrorCode() === 'ERR_BAD_REVISION') {
    // nonexistent or policy-hidden revision: skip or report 404-equivalent
  } else {
    throw $ex;
  }
}

Prevention

When it happens

Trigger: Calling differential.getrevision with a nonexistent revision_id; passing the monogram string 'D123' instead of the integer 123; passing 0 or a negative number; using a token whose user cannot see the revision because of its view policy or a governing project policy.

Common situations: Scripts that extract 'D123' from a commit message and forward it verbatim; migration or reporting jobs that run after revisions were deleted; bot accounts that are not members of the project that governs the revision; clients pointed at the wrong Phabricator instance where the ID does not exist.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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