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

  1. If multiple rows are legitimate, switch to loadAllWhere() and pick deterministically (ORDER BY id, take head) or handle the ambiguity explicitly
  2. If uniqueness is an invariant, find and merge/delete the duplicate rows, then add a UNIQUE index so the database enforces it
  3. Tighten the WHERE pattern with additional conditions until it identifies one row
  4. 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

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


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