phacility/phabricator · error · Exception

Unable to reload object that hasn't been loaded!

Error message

Unable to reload object that hasn't been loaded!

What it means

LiskDAO::reload() re-fetches the object's row by primary key, so it requires an ID. An object that was constructed with new but never save()d (or loaded) has no ID, and reload() throws immediately. A second failure mode sits right below this check: if the ID exists but the row was deleted, you get AphrontObjectMissingQueryException instead.

Source

Thrown at src/infrastructure/storage/lisk/LiskDAO.php:554

    array_push($args, $lock_clause);
    array_unshift($args, $pattern);

    return call_user_func_array(array($conn, 'queryData'), $args);
  }


  /**
   * Reload an object from the database, discarding any changes to persistent
   * properties. This is primarily useful after entering a transaction but
   * before applying changes to an object.
   *
   * @return this
   *
   * @task   load
   */
  public function reload() {
    if (!$this->getID()) {
      throw new Exception(
        pht("Unable to reload object that hasn't been loaded!"));
    }

    $result = $this->loadOneWhere(
      '%C = %d',
      $this->getIDKey(),
      $this->getID());

    if (!$result) {
      throw new AphrontObjectMissingQueryException();
    }

    return $this;
  }


  /**
   * Initialize this object's properties from a dictionary. Generally, you

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Persist first: call $obj->save() (or load the object from the database) before reload()
  2. Guard mixed-state code with if ($obj->getID()) { $obj->reload(); }
  3. Restructure creation flows so 'reload existing' and 'create new' are separate branches
  4. If you hit the related AphrontObjectMissingQueryException, the row was deleted concurrently — handle that separately

Example fix

// before: reload on a possibly-new object
function refresh(MyDAO $obj) {
  return $obj->reload();
}

// after: only persisted objects can be reloaded
function refresh(MyDAO $obj) {
  if (!$obj->getID()) {
    return $obj; // never saved: nothing to reload
  }
  return $obj->reload();
}
Defensive patterns

Strategy: validation

Validate before calling

// Only persisted objects have an ID to reload by:
if ($obj->getID()) {
  $obj->reload();
}

Type guard

/** True once a LiskDAO has been persisted (has a primary key). */
function dao_is_persisted(LiskDAO $dao) {
  return (bool)$dao->getID();
}

// Usage:
if (dao_is_persisted($object)) {
  $object->reload();
}

Prevention

When it happens

Trigger: Calling reload() on a freshly built DAO before save(); shared code paths that receive sometimes-new sometimes-persisted objects; tests building fixtures and forgetting to persist them; calling reload() inside a workflow that starts from raw user input.

Common situations: Helper functions that 'refresh' objects regardless of state; copy-pasting load-then-reload patterns onto creation flows; fixtures in unit tests that skip the save step.

Related errors


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