{"record":{"id":"2d20c12be93ba10d","repo":"phacility/phabricator","slug":"unable-to-establish-a-write-mode-connection-to-ap","errorCode":null,"errorMessage":"Unable to establish a write-mode connection (to application database \"%s\") because this server is in read-only mode. Whatever you are trying to do does not function correctly in read-only mode.","messagePattern":"Unable to establish a write-mode connection \\(to application database \"(.+?)\"\\) because this server is in read-only mode\\. Whatever you are trying to do does not function correctly in read-only mode\\.","errorType":"exception","errorClass":"PhabricatorClusterImproperWriteException","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/lisk/PhabricatorLiskDAO.php","lineNumber":138,"sourceCode":"              'into read-only mode.',\n              $database),\n            $master_exception);\n          phlog($proxy_exception);\n        }\n\n        return $connection;\n      }\n    }\n\n    if (!$master && !$replica) {\n      $this->raiseUnconfigured($database);\n    }\n\n    $this->raiseUnreachable($database, $master_exception);\n  }\n\n  private function raiseImproperWrite($database) {\n    throw new PhabricatorClusterImproperWriteException(\n      pht(\n        'Unable to establish a write-mode connection (to application '.\n        'database \"%s\") because this server is in read-only mode. Whatever '.\n        'you are trying to do does not function correctly in read-only mode.',\n        $database));\n  }\n\n  private function raiseImpossibleWrite($database) {\n    throw new PhabricatorClusterImpossibleWriteException(\n      pht(\n        'Unable to connect to master database (\"%s\"). This is a severe '.\n        'failure; your request did not complete.',\n        $database));\n  }\n\n  private function raiseUnconfigured($database) {\n    throw new Exception(\n      pht(","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php#L120-L156","documentation":"Write access is gated on PhabricatorEnv::isReadOnly() (see PhabricatorLiskDAO.php:63): when the process is in read-only mode, requesting a write-mode connection is refused locally with PhabricatorClusterImproperWriteException before any server is contacted. This exists to keep replicas safe during disaster recovery, failover, or maintenance windows, when the surviving infrastructure must not receive writes.","triggerScenarios":"The server/host is configured read-only (cluster configuration, disaster-recovery mode) and code requests a write connection; long-lived daemons or workers started before read-only mode was enabled later try to write; web processes handling POST endpoints during a read-only window.","commonSituations":"Failover to replica-only infrastructure during a master outage; maintenance/upgrade windows where the cluster is deliberately read-only; a daemon that predates the mode switch continuing its queue.","solutions":["Finish or defer the read-only operation: queue the write, or surface 'temporarily read-only' to the user","When writing is intended again, restore a writable master and clear the read-only state in configuration","Gate write paths in your code on PhabricatorEnv::isReadOnly() and degrade gracefully instead of letting the exception escape","Restart daemons/workers after entering or leaving read-only mode so their behavior matches the current mode"],"exampleFix":"// before: blind write during a read-only window\n$task->save();\n\n// after: check the mode and defer\nif (PhabricatorEnv::isReadOnly()) {\n  // Queue or report; do not attempt the write.\n  return $this->newErrorResult(pht('This system is temporarily read-only.'));\n}\n$task->save();","handlingStrategy":"validation","validationCode":"// Gate every write path on the current mode (same check the DAO layer uses):\nif (PhabricatorEnv::isReadOnly()) {\n  // Defer: queue the write, or return a clear 'temporarily read-only' result.\n  return $this->newReadOnlyError();\n}\n$object->save();","typeGuard":null,"tryCatchPattern":"try {\n  $conn = $dao->establishConnection('w');\n} catch (PhabricatorClusterImproperWriteException $ex) {\n  // Expected during failover/maintenance: queue or defer the write; do not retry now.\n}","preventionTips":["Check PhabricatorEnv::isReadOnly() before writes in any code that runs during maintenance windows","Design write paths with a deferral mechanism (queue, retry-later) rather than assuming writes always succeed","Restart daemons and workers after toggling read-only mode so their behavior matches","Communicate read-only windows to users (banner) instead of letting raw exceptions surface"],"tags":["cluster","read-only","writes","failover","high-availability"],"backgroundTag":"write-to-read-only-database","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}