phacility/phabricator · error · ConduitException
ERR_CLOSED
ERR_CLOSED
Error message
ERR_CLOSED
What it means
Once a revision isPublished() — its change landed and the revision was closed — differential.updaterevision refuses further edits and throws ERR_CLOSED before applying any field edit. In Differential's model a closed revision is a historical record; new work requires a new revision.
Source
Thrown at src/applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php:73
}
$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
- Create a new revision for follow-up changes instead of updating the closed one.
- If the close itself was wrong, reopen the revision first (the revision 'Reopen' command/action) and retry.
- Guard the call: load the revision and skip when its status is published/closed.
Example fix
// before
$client->callMethodSynchronous('differential.updaterevision', $params);
// after
$result = $client->callMethodSynchronous('differential.revision.search', array(
'constraints' => array('ids' => array($revision_id)),
));
$status = idx(idx(idx($result, 'data', array()), 0, array()), 'fields', array());
if (idx(idx($status, 'status', array()), 'value') === 'published') {
// closed: create a new revision instead
return;
}
$client->callMethodSynchronous('differential.updaterevision', $params); Defensive patterns
Strategy: validation
Validate before calling
$result = $client->callMethodSynchronous('differential.revision.search', array(
'constraints' => array('ids' => array($revision_id)),
));
$revision = idx(idx($result, 'data', array()), 0, array());
$status_value = idx(idx(idx($revision, 'fields', array()), 'status', array()), 'value');
if ($status_value === 'published') {
// closed: create a new revision instead of updating
return;
} Try / catch
try {
$result = $client->callMethodSynchronous(
'differential.updaterevision', $params);
} catch (ConduitClientException $ex) {
if ($ex->getErrorCode() === 'ERR_CLOSED') {
// permanent for this revision: create a new revision, do not retry
} else {
throw $ex;
}
} Prevention
- Treat closed revisions as immutable; create a new revision for follow-up work.
- Check the revision status before attempting updates.
- Never retry ERR_CLOSED — it only clears if an admin reopens the revision.
When it happens
Trigger: Calling differential.updaterevision on a revision that was closed by arc land, by commit detection, or by a manual close action.
Common situations: Automation retrying an update after the branch already landed; developers who keep working on a topic after landing and push updates to the old revision.
Related errors
- ERR_NOT_FOUND
- ERR_BAD_REVISION
- Unsupported action "%s".
- Field "changes" must be non-empty.
- ERR-BAD-REVISION
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/defa317440f608f2.
Report an issue: GitHub.