passbolt/passbolt_api · error · CakeException
Could not read the file
Error message
Could not read the file: {0} What it means
In KeyringInitCommand, after confirming the private key file exists, file_get_contents() returns false (PHP warning suppressed by @ or checked here) when the file cannot be read — typically due to filesystem permissions, unreadable ownership, or an I/O problem. The command throws because it cannot import a key it cannot read.
Solutions
- Fix ownership/permissions: chown www-data:www-data <keyfile> && chmod 600 <keyfile>, then re-run keyring init as the web server user.
- Run the command as the same user that owns the key: sudo su -s /bin/bash -c './bin/cake passbolt keyring init' www-data.
- Check the path is a regular file (ls -l) and the parent directories grant +x traversal.
- If SELinux denies access, restore correct context (restorecon) or check audit logs (ausearch -m avc).
Example fix
// before: root-owned key, command runs as www-data -> read fails -rw------- root root /etc/passbolt/serverkey_private.asc // after $ chown www-data:www-data /etc/passbolt/serverkey_private.asc && chmod 600 /etc/passbolt/serverkey_private.asc $ sudo su -s /bin/bash -c './bin/cake passbolt keyring init' www-data
Defensive patterns
Strategy: type-guard
Validate before calling
$path = Configure::read('passbolt.gpg.serverKey.private');
if (!is_file($path) || !is_readable($path)) {
fwrite(STDERR, "Cannot read key file '{$path}' as user " . get_current_user() . ". Check owner/permissions.\n");
exit(1);
} Try / catch
try {
$this->KeyringInitCommand->execute($args, $io);
} catch (CakeException $e) {
if (str_starts_with($e->getMessage(), 'Could not read the file')) {
// chown/chmod the key for the current user, or re-run as its owner
}
} Prevention
- Always run passbolt CLI commands as the web server user (www-data).
- Keep server key owned by www-data with mode 600 and traversable parent dirs.
- Check SELinux/AppArmor policies when access looks correct but still fails.
- Re-apply ownership after restoring or copying key files.
When it happens
Trigger: file_exists() passes but file_get_contents() fails on passbolt.gpg.serverKey.private: file owned by root with mode 600 while command runs as www-data, directory without execute permission, SELinux/AppArmor denial, or the path is a directory/special file.
Common situations: Key generated as root then command run as www-data (or vice versa); Docker image where key is mounted root-owned 600; SELinux enforcing on RHEL/Fedora; NFS/permissions issues after restore.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- The file does not exist
- Missing metadata private key.
- The file could not be read.
- The OpenPGP public key file '$publicKeyFileName' is not…
- group(s) returned by your directory are invalid and will be…
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/f3c50086b97927ba.
Report an issue: GitHub.
Appendix: source
Thrown at src/Command/KeyringInitCommand.php:68
/**
* @inheritDoc
*/
public function execute(Arguments $args, ConsoleIo $io): ?int
{
parent::execute($args, $io);
// Root user is not allowed to execute this command.
$this->assertCurrentProcessUser($io, $this->processUserService);
try {
$filePath = Configure::read('passbolt.gpg.serverKey.private');
if (!file_exists($filePath)) {
throw new CakeException(__('The file does not exist: {0}', $filePath));
}
$armoredKey = file_get_contents($filePath);
if ($armoredKey === false) {
throw new CakeException(__('Could not read the file: {0}', $filePath));
}
// Import the private key in the OpenPGP keyring
$gpg = OpenPGPBackendFactory::get();
$io->out('Importing ' . $filePath);
$gpg->importKeyIntoKeyring($armoredKey);
} catch (CakeException $e) {
$this->error($e->getMessage(), $io);
$this->error('Could not import the server OpenPGP key into the keyring.', $io);
return $this->errorCode();
}
$this->success('Keyring init OK', $io);
return $this->successCode();
}
}View on GitHub (pinned to 31c1bbc10f)