passbolt/passbolt_api · error · BadRequestException

Provided root CA file does not exist

Error message

Provided root CA file does not exist

What it means

This BadRequestException is thrown by SsoHttpClientFactory::resolveVerify when the `passbolt.security.sso.sslCafile` config points to a path that does not exist on the server filesystem. The library validates the CA bundle path before wiring it into the HTTP client used for SSO/OAuth2 TLS verification, failing fast to avoid silent certificate trust issues later.

Solutions

  1. Check the configured path with `ls -l` on the server (inside the container if applicable) and fix `passbolt.security.sso.sslCafile` in config/passbolt.php or environment config to point at an existing CA bundle.
  2. If no custom CA is needed, remove/unset the sslCafile config entry so resolveVerify returns early and uses system defaults.
  3. If the CA file lives outside the container, mount it into the container and reference the in-container path.
  4. Ensure the file is readable by the web-server/PHP user (existence also implies readable for file_exists, but verify permissions for fopen).

Example fix

// before
'passbolt' => ['security' => ['sso' => ['sslCafile' => '/etc/ssl/custom-ca.pem']]], // file absent
// after
'passbolt' => ['security' => ['sso' => ['sslCafile' => '/etc/ssl/certs/ca-certificates.crt']]], // verified with ls
Defensive patterns

Strategy: validation

Validate before calling

$cafile = Configure::read('passbolt.security.sso.sslCafile');
if (is_string($cafile) && !file_exists($cafile)) {
    throw new RuntimeException("sslCafile does not exist: $cafile");
}

Type guard

function isValidCafilePath(mixed $path): bool {
    return is_string($path) && $path !== '' && file_exists($path) && is_readable($path);
}

Try / catch

try {
    $client = SsoHttpClientFactory::create();
} catch (BadRequestException $e) {
    // check passbolt.security.sso.sslCafile points to an existing file
}

Prevention

When it happens

Trigger: Calling SsoHttpClientFactory::create() while `passbolt.security.sso.sslCafile` is set to a string path that passes the is_string check but fails file_exists() — e.g. a typo'd path, a deleted file, or a path valid on another machine/container.

Common situations: Admins copy config from docs where the CA path differs per OS (/etc/ssl/certs/ca-certificates.crt vs /etc/pki/tls/certs/ca-bundle.crt); Docker volumes not mounting the CA file; the file was removed during a base image change or cert package update.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/1e67d11d9be1e8b1. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Utility/Http/SsoHttpClientFactory.php:73

     * @return string|bool `true` for default verification, `false` to disable, or a CA file path.
     * @throws \Cake\Http\Exception\BadRequestException When a custom CA file is configured but invalid.
     */
    private static function resolveVerify(): bool|string
    {
        $sslVerify = (bool)Configure::read(self::CONFIG_SSL_VERIFY, true);
        $sslCafile = Configure::read(self::CONFIG_SSL_CAFILE);

        if ($sslVerify && $sslCafile === null) {
            return true;
        }
        if (!$sslVerify) {
            return false;
        }
        if (!is_string($sslCafile)) {
            throw new BadRequestException(__('Invalid value provided in `passbolt.security.sso.sslCafile` config'));
        }
        if (!file_exists($sslCafile)) {
            throw new BadRequestException(__('Provided root CA file does not exist'));
        }

        return $sslCafile;
    }
}

View on GitHub (pinned to 31c1bbc10f)