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

  1. Finish or defer the read-only operation: queue the write, or surface 'temporarily read-only' to the user
  2. When writing is intended again, restore a writable master and clear the read-only state in configuration
  3. Gate write paths in your code on PhabricatorEnv::isReadOnly() and degrade gracefully instead of letting the exception escape
  4. 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

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


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