phacility/phabricator · error · PhabricatorClusterImproperWriteException
Unable to establish a write-mode connection (to application
Error message
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.
What it means
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.
Source
Thrown at src/infrastructure/storage/lisk/PhabricatorLiskDAO.php:138
'into read-only mode.',
$database),
$master_exception);
phlog($proxy_exception);
}
return $connection;
}
}
if (!$master && !$replica) {
$this->raiseUnconfigured($database);
}
$this->raiseUnreachable($database, $master_exception);
}
private function raiseImproperWrite($database) {
throw new PhabricatorClusterImproperWriteException(
pht(
'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.',
$database));
}
private function raiseImpossibleWrite($database) {
throw new PhabricatorClusterImpossibleWriteException(
pht(
'Unable to connect to master database ("%s"). This is a severe '.
'failure; your request did not complete.',
$database));
}
private function raiseUnconfigured($database) {
throw new Exception(
pht(View on GitHub (pinned to 5720a38cfe)
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
Example fix
// before: blind write during a read-only window
$task->save();
// after: check the mode and defer
if (PhabricatorEnv::isReadOnly()) {
// Queue or report; do not attempt the write.
return $this->newErrorResult(pht('This system is temporarily read-only.'));
}
$task->save(); Defensive patterns
Strategy: validation
Validate before calling
// Gate every write path on the current mode (same check the DAO layer uses):
if (PhabricatorEnv::isReadOnly()) {
// Defer: queue the write, or return a clear 'temporarily read-only' result.
return $this->newReadOnlyError();
}
$object->save(); Try / catch
try {
$conn = $dao->establishConnection('w');
} catch (PhabricatorClusterImproperWriteException $ex) {
// Expected during failover/maintenance: queue or defer the write; do not retry now.
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unable to connect to master database ("%s"). This is a sever
- This server is currently in read-only mode. Use --force to o
- This host has device ID "%s", but there is no corresponding
- Configuration file specifies cluster peer ("%s", at index "%
- Configuration file specifies cluster peer "%s" more than onc
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/2d20c12be93ba10d.
Report an issue: GitHub.