passbolt/passbolt_api · error · SubscriptionException
The file could not be read.
Error message
The file {0} could not be read. What it means
SubscriptionKeyImportService::importFromFile() calls is_readable($fileName) after confirming the file exists; if the filesystem denies read access it throws SubscriptionException 'The file {0} could not be read.'
Solutions
- Chown/chmod the file so the web/CLI PHP user can read it: chown www-data file && chmod 640 file
- Check the directory's execute permission too (the PHP user must be able to traverse to the file)
- Inspect SELinux/AppArmor denials in audit logs if permissions look correct
Example fix
// shell before -rw------- root root /etc/passbolt/subscription.txt // shell after -rw-r----- www-data www-data /etc/passbolt/subscription.txt
Defensive patterns
Strategy: validation
Validate before calling
if (!is_readable($path)) { throw new RuntimeException("Cannot read $path as user " . get_current_user()); } Type guard
null
Try / catch
try { $svc->importFromFile($path, $uac); } catch (SubscriptionException $e) { // fix file ownership/permissions } Prevention
- Deploy license files owned by the PHP runtime user
- Use chmod 640 and correct group ownership
- Audit SELinux/AppArmor policies in hardened environments
When it happens
Trigger: Import invoked on an existing license file whose OS permissions, owner, or SELinux/AppArmor context prevent the PHP process user from reading it.
Common situations: License file uploaded by root or owned by another user (e.g. 0600 root:root) while PHP runs as www-data; restrictive umask after manual copy; Docker volume mounted with wrong ownership.
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 could not be found.
- Could not read the file
- Only administrators can update the subscription details.
- Only administrators can view the subscription details.
- Subscription key could not be found.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/8a2ee4244e9b7710.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Subscription/src/Service/Subscriptions/SubscriptionKeyImportService.php:40
/**
* Persists a subscription key supplied via file or text.
*/
class SubscriptionKeyImportService
{
/**
* @param string $fileName Path to a file containing the subscription key.
* @param \App\Utility\UserAccessControl $uac UAC object.
* @return \Passbolt\Subscription\Model\Dto\SubscriptionKeyDto
* @throws \Passbolt\Subscription\Error\Exception\Subscriptions\SubscriptionException If the file or the contained subscription is not valid.
*/
public function importFromFile(string $fileName, UserAccessControl $uac): SubscriptionKeyDto
{
if (!file_exists($fileName)) {
throw new SubscriptionException(__('The file {0} could not be found.', $fileName));
}
if (!is_readable($fileName)) {
throw new SubscriptionException(__('The file {0} could not be read.', $fileName));
}
$subscription = file_get_contents($fileName);
if (!$subscription) {
throw new SubscriptionException(__('The file {0} could not be read.', $fileName));
}
return $this->import($subscription, $uac);
}
/**
* @param string|null $subscription Raw subscription key payload (Base64).
* @param \App\Utility\UserAccessControl $uac UAC object.
* @return \Passbolt\Subscription\Model\Dto\SubscriptionKeyDto
* @throws \Passbolt\Subscription\Error\Exception\Subscriptions\SubscriptionException If the subscription is not valid.
*/
public function import(?string $subscription, UserAccessControl $uac): SubscriptionKeyDto
{
return (new SubscriptionKeySaveService())->save($subscription, $uac);View on GitHub (pinned to 31c1bbc10f)