phacility/phabricator · error · ConduitException
ERR_BAD_REVISION
ERR_BAD_REVISION
Error message
ERR_BAD_REVISION
What it means
The revision referenced by id must exist and the acting user must hold both CAN_VIEW and CAN_EDIT on it (the query calls requireCapabilities). Nonexistent, invisible, and non-editable revisions all surface as ERR_BAD_REVISION, so this single code covers both not-found and permission failure.
Source
Thrown at src/applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php:69
->withIDs(array($request->getValue('diffid')))
->executeOne();
if (!$diff) {
throw new ConduitException('ERR_BAD_DIFF');
}
$revision = id(new DifferentialRevisionQuery())
->setViewer($request->getUser())
->withIDs(array($request->getValue('id')))
->needReviewers(true)
->needActiveDiffs(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$revision) {
throw new ConduitException('ERR_BAD_REVISION');
}
if ($revision->isPublished()) {
throw new ConduitException('ERR_CLOSED');
}
$this->applyFieldEdit(
$request,
$revision,
$diff,
$request->getValue('fields', array()),
$request->getValue('message'));
return array(
'revisionid' => $revision->getID(),
'uri' => PhabricatorEnv::getURI('/D'.$revision->getID()),
);
}View on GitHub (pinned to 5720a38cfe)
Solutions
- Confirm the numeric revision id (no 'D' prefix).
- Ensure the conduit user is the revision author or otherwise has edit rights.
- Pre-check visibility with differential.revision.search as the same user; an invisible revision fails the same way.
- Check you are on the instance that owns the revision.
Example fix
// before: update runs as a bot that cannot edit the revision
$client->callMethodSynchronous('differential.updaterevision', array(
'id' => 123,
'diffid' => 456,
));
// after: run as the revision author's token, numeric ids only
$client->callMethodSynchronous('differential.updaterevision', array(
'id' => 123,
'diffid' => 456,
)); Defensive patterns
Strategy: validation
Validate before calling
$result = $client->callMethodSynchronous('differential.revision.search', array(
'constraints' => array('ids' => array($revision_id)),
));
if (empty($result['data'])) {
throw new RuntimeException(
'Revision missing or not visible to this user.');
} Type guard
function isRevisionID($value) {
return is_int($value) && $value > 0;
} Try / catch
try {
$result = $client->callMethodSynchronous(
'differential.updaterevision', $params);
} catch (ConduitClientException $ex) {
if ($ex->getErrorCode() === 'ERR_BAD_REVISION') {
// not found or no edit rights: re-check id, author, and policies
} else {
throw $ex;
}
} Prevention
- Update revisions only as their author or a user with edit rights.
- Pre-check visibility with differential.revision.search under the same token.
- Send numeric ids only, without the 'D' prefix.
When it happens
Trigger: id is wrong or nonexistent; the user is not the author and has no edit rights; the view policy hides the revision so the policy-filtered query returns null; the ID is prefixed with 'D'.
Common situations: Bots or teammates trying to update someone else's revision; a revision moved under a restrictive project policy; ID mix-ups across instances; automation running with the wrong token.
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
- ERR_BAD_REVISION
- ERR_NOT_FOUND
- ERR_BAD_REVISION
- Unsupported action "%s".
- Field "changes" must be non-empty.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/57c6c1a0f1a31b78.
Report an issue: GitHub.