phacility/phabricator · error · AphrontCountQueryException
More than one result from %s!
Error message
More than one result from %s!
What it means
loadOneWhere() promises at most one matching row; when the WHERE pattern matches several, it throws AphrontCountQueryException instead of returning an arbitrary row. This enforces uniqueness assumptions at the API boundary. If the column genuinely is not unique, the caller is using the wrong method (loadAllWhere) or the data violates an invariant the code relies on.
Source
Thrown at src/infrastructure/storage/lisk/LiskDAO.php:505
* Load a single object identified by a 'WHERE' clause. You provide
* everything after the 'WHERE', and Lisk builds the first half of the
* query. See loadAllWhere(). This method is similar, but returns a single
* result instead of a list.
*
* @param string queryfx()-style SQL WHERE clause.
* @param ... Zero or more conversions.
* @return obj|null Matching object, or null if no object matches.
*
* @task load
*/
public function loadOneWhere($pattern /* , $arg, $arg, $arg ... */) {
$args = func_get_args();
$data = call_user_func_array(
array($this, 'loadRawDataWhere'),
$args);
if (count($data) > 1) {
throw new AphrontCountQueryException(
pht(
'More than one result from %s!',
__FUNCTION__.'()'));
}
$data = reset($data);
if (!$data) {
return null;
}
return $this->loadFromArray($data);
}
protected function loadRawDataWhere($pattern /* , $args... */) {
$conn = $this->establishConnection('r');
if ($conn->isReadLocking()) {View on GitHub (pinned to 5720a38cfe)
Solutions
- If multiple rows are legitimate, switch to loadAllWhere() and pick deterministically (ORDER BY id, take head) or handle the ambiguity explicitly
- If uniqueness is an invariant, find and merge/delete the duplicate rows, then add a UNIQUE index so the database enforces it
- Tighten the WHERE pattern with additional conditions until it identifies one row
- For create-or-get patterns, combine with catching AphrontDuplicateKeyQueryException on insert
Example fix
// before: field is not unique; dies when two rows match
$session = $object->loadOneWhere('sessionKey = %s', $key);
// after (a): duplicates are legal — decide deterministically
$sessions = $object->loadAllWhere(
'sessionKey = %s ORDER BY id ASC',
$key);
$session = head($sessions);
// after (b): uniqueness is intended — enforce it, then keep loadOneWhere()
// 1) deduplicate rows, 2) ALTER TABLE ... ADD UNIQUE KEY (sessionKey) Defensive patterns
Strategy: try-catch
Validate before calling
// Prefer the right loader up front: use loadOneWhere() only on columns // you know are UNIQUE; otherwise go straight to loadAllWhere(): $rows = id(new MyDAO())->loadAllWhere( 'label = %s ORDER BY id ASC', $label); $match = head($rows); // decide deterministically when several match
Try / catch
try {
$obj = id(new MyDAO())->loadOneWhere('%C = %s', $key, $value);
} catch (AphrontCountQueryException $ex) {
// Uniqueness assumption violated: fall back to a deterministic pick
// (and alert — duplicates usually mean a missing UNIQUE index).
$all = id(new MyDAO())->loadAllWhere(
'%C = %s ORDER BY id ASC',
$key,
$value);
$obj = head($all);
} Prevention
- Use loadOneWhere() only with primary keys or columns backed by a UNIQUE index
- Back every uniqueness assumption with a real UNIQUE index so duplicates cannot appear
- When a value may legitimately repeat, write the loadAllWhere + head() pattern from the start
- Investigate every occurrence instead of silently taking the first row — it signals data drift
When it happens
Trigger: loadOneWhere() on a non-unique column (status, authorPHID, a label that repeats); duplicates existing in a column the code assumes unique (two rows with the same PHID or email after a bad import or race); a WHERE clause that is not selective enough for the data.
Common situations: Code written when a value happened to be unique, later violated by new data; missing UNIQUE index allowing duplicates to accumulate; imports that upserted incorrectly; lookup-by-slug/name where collisions are legal.
Related errors
- Unable to reload object that hasn't been loaded!
- Rows passed to "loadAllFromArray(...)" include two or more r
- Event queries which generate ghost events must include eithe
- Document already exists!
- Expected a query key or a set of query constraints.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/1e5fabdc57ec2365.
Report an issue: GitHub.