{"record":{"id":"883aead603197554","repo":"phacility/phabricator","slug":"unable-to-reload-object-that-hasn-t-been-loaded","errorCode":null,"errorMessage":"Unable to reload object that hasn't been loaded!","messagePattern":"Unable to reload object that hasn't been loaded!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/lisk/LiskDAO.php","lineNumber":554,"sourceCode":"    array_push($args, $lock_clause);\n    array_unshift($args, $pattern);\n\n    return call_user_func_array(array($conn, 'queryData'), $args);\n  }\n\n\n  /**\n   * Reload an object from the database, discarding any changes to persistent\n   * properties. This is primarily useful after entering a transaction but\n   * before applying changes to an object.\n   *\n   * @return this\n   *\n   * @task   load\n   */\n  public function reload() {\n    if (!$this->getID()) {\n      throw new Exception(\n        pht(\"Unable to reload object that hasn't been loaded!\"));\n    }\n\n    $result = $this->loadOneWhere(\n      '%C = %d',\n      $this->getIDKey(),\n      $this->getID());\n\n    if (!$result) {\n      throw new AphrontObjectMissingQueryException();\n    }\n\n    return $this;\n  }\n\n\n  /**\n   * Initialize this object's properties from a dictionary. Generally, you","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/lisk/LiskDAO.php#L536-L572","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: reload on a possibly-new object\nfunction refresh(MyDAO $obj) {\n  return $obj->reload();\n}\n\n// after: only persisted objects can be reloaded\nfunction refresh(MyDAO $obj) {\n  if (!$obj->getID()) {\n    return $obj; // never saved: nothing to reload\n  }\n  return $obj->reload();\n}","handlingStrategy":"validation","validationCode":"// Only persisted objects have an ID to reload by:\nif ($obj->getID()) {\n  $obj->reload();\n}","typeGuard":"/** True once a LiskDAO has been persisted (has a primary key). */\nfunction dao_is_persisted(LiskDAO $dao) {\n  return (bool)$dao->getID();\n}\n\n// Usage:\nif (dao_is_persisted($object)) {\n  $object->reload();\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["lisk","dao","object-state","unsaved-object","api-misuse"],"backgroundTag":"operation-on-unsaved-object","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}