phacility/phabricator · error · ConduitException
ERR_BAD_DIFF
ERR_BAD_DIFF
Error message
ERR_BAD_DIFF
What it means
Thrown by the differential.getdiff Conduit method in its revision branch. When revision_id is supplied, the method queries all diffs attached to that revision (withRevisionIDs) and takes the newest; if the query returns no diffs at all - wrong ID, revision invisible to the viewer, or a revision with zero attached diffs - ConduitException('ERR_BAD_DIFF') is thrown before the diff is loaded.
Source
Thrown at src/applications/differential/conduit/DifferentialGetDiffConduitAPIMethod.php:62
'ERR_BAD_DIFF' => pht('No such diff exists.'),
);
}
protected function execute(ConduitAPIRequest $request) {
$diff_id = $request->getValue('diff_id');
// If we have a revision ID, we need the most recent diff. Figure that out
// without loading all the attached data.
$revision_id = $request->getValue('revision_id');
if ($revision_id) {
$diffs = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withRevisionIDs(array($revision_id))
->execute();
if ($diffs) {
$diff_id = head($diffs)->getID();
} else {
throw new ConduitException('ERR_BAD_DIFF');
}
}
$diff = null;
if ($diff_id) {
$diff = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withIDs(array($diff_id))
->needChangesets(true)
->executeOne();
}
if (!$diff) {
throw new ConduitException('ERR_BAD_DIFF');
}
return $diff->getDiffDict();
}View on GitHub (pinned to 5720a38cfe)
Solutions
- Verify the revision exists and is visible via differential.query before calling
- If you already know the diff, pass diff_id directly and skip the revision lookup
- Send revision_id as a bare integer
- Catch ERR_BAD_DIFF distinctly: here it means 'no diffs for revision', not necessarily a bad diff id
Example fix
// before
$params = array('revision_id' => 'D77');
// after
$params = array('revision_id' => 77); Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the revision has diffs before fetching.
$found = $client->callMethodSynchronous('differential.query',
array('ids' => array((int)$rev_id)));
if (!$found) {
throw new InvalidArgumentException('Unknown revision '.$rev_id);
} Try / catch
try {
$dict = $client->callMethodSynchronous('differential.getdiff',
array('revision_id' => (int)$rev_id));
} catch (ConduitClientException $ex) {
if ($ex->getErrorCode() === 'ERR_BAD_DIFF') {
// revision unknown/invisible or has no diffs
} else {
throw $ex;
}
} Prevention
- Send bare integer revision ids
- When you know the diff, pass diff_id and skip the revision branch
- Pre-check visibility with differential.query for IDs from untrusted sources
When it happens
Trigger: Calling differential.getdiff with a revision_id that does not exist, is 'D'-prefixed, is invisible to the caller, or names a revision that has no diffs yet.
Common situations: Automation fetching the current diff for a revision number parsed from a branch name; restricted spaces hiding the revision; passing a PHID instead of the integer ID.
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/7694532b13e0b287.
Report an issue: GitHub.