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, youView on GitHub (pinned to 5720a38cfe)
Solutions
- Persist first: call $obj->save() (or load the object from the database) before reload()
- Guard mixed-state code with if ($obj->getID()) { $obj->reload(); }
- Restructure creation flows so 'reload existing' and 'create new' are separate branches
- 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
- Call reload() only on objects obtained via load/save flows, never on freshly constructed ones
- Guard shared helpers with getID() when they can receive new and persisted objects alike
- In tests, always save() fixtures before exercising reload paths
- Handle the sibling case AphrontObjectMissingQueryException for rows deleted concurrently
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
- More than one result from %s!
- Rows passed to "loadAllFromArray(...)" include two or more r
- 1062
- 1146, 1049, 1054
- No storage namespace configured!
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/883aead603197554.
Report an issue: GitHub.