phacility/phabricator · critical · PhutilProxyException

Configuration file "%s" exists, but could not be read.

Error message

Configuration file "%s" exists, but could not be read.

What it means

PhabricatorConfigLocalSource loads conf/local/local.json, the instance-local configuration override file. If the path exists but Filesystem::readFile() throws (unreadable permissions, removed mid-read, path is a directory, safe-mode restriction), the FilesystemException is wrapped in PhutilProxyException with this message and every config read that needs the local source fails. This is a boot-level failure: the local source participates in config stack construction, so the web UI and CLI both break until it is fixed.

Source

Thrown at src/infrastructure/env/PhabricatorConfigLocalSource.php:32

  }

  public function deleteKeys(array $keys) {
    $result = parent::deleteKeys($keys);
    $this->saveConfig();
    return parent::deleteKeys($keys);
  }

  private function loadConfig() {
    $path = $this->getConfigPath();

    if (!Filesystem::pathExists($path)) {
      return array();
    }

    try {
      $data = Filesystem::readFile($path);
    } catch (FilesystemException $ex) {
      throw new PhutilProxyException(
        pht(
          'Configuration file "%s" exists, but could not be read.',
          $path),
        $ex);
    }

    try {
      $result = phutil_json_decode($data);
    } catch (PhutilJSONParserException $ex) {
      throw new PhutilProxyException(
        pht(
          'Configuration file "%s" exists and is readable, but the content '.
          'is not valid JSON. You may have edited this file manually and '.
          'introduced a syntax error by mistake. Correct the file syntax '.
          'to continue.',
          $path),
        $ex);
    }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Fix read permission and ownership for the web/daemon user: chmod 644 conf/local/local.json (or 640 with matching group) and chown it to the account running PHP.
  2. Confirm the path is a regular file: ls -la conf/local/local.json; if it was replaced by a directory or symlink loop, restore a real file.
  3. Verify by running `./bin/config get` as the web user; it should now parse the JSON (a follow-up PhabricatorConfigLocalSource error will appear if syntax is broken).

Example fix

# before: unreadable by the web user
$ ls -l conf/local/local.json
-rw------- 1 root root 532 local.json

# after
$ sudo chown www-data:www-data conf/local/local.json
$ sudo chmod 640 conf/local/local.json
Defensive patterns

Strategy: validation

Validate before calling

$path = 'conf/local/local.json';
if (file_exists($path) && !is_readable($path)) {
  throw new Exception("Fix permissions before continuing: $path");
}

Prevention

When it happens

Trigger: chmod/chown that removes read permission from conf/local/local.json (root-owned after running daemons as root, then serving as www-data); the file being replaced by a directory; a container image that copied the file with mode 600 for another UID; disk/FS errors surfaced as FilesystemException.

Common situations: After automation or restoring backups as root, file ownership becomes root:root and the PHP-FPM user cannot read it; hardening playbooks that recursively tighten permissions under conf/; Docker/Kubernetes volume mounts overriding file modes.

Related errors


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