passbolt/passbolt_api · error · CustomValidationException
The role could not be saved.
Error message
The role could not be saved.
What it means
RolesAddService::add throws this CustomValidationException when the Roles table's saveOrFail raises a PersistenceFailedException, i.e. the new role entity failed model rules/rulesChecker before INSERT. The entity's field errors are attached so the API can report which fields were rejected.
Solutions
- Read the `errors` payload in the 400 response to identify the failing field (usually name).
- Verify the role name is unique: GET /roles and check for an existing entry.
- Resend POST /roles with a valid, non-empty, unique name.
- If persistence fails repeatedly without a clear field error, check DB connectivity/constraints and the Roles table rules.
Example fix
// before
POST /roles {"name": "admin"} // already exists -> 400
// after
POST /roles {"name": "auditor"} // unique -> 201 Defensive patterns
Strategy: validation
Validate before calling
function validRoleName(name) {
return typeof name === 'string' && name.trim().length > 0 && name.length <= 255;
}
if (!validRoleName(roleName)) throw new Error('Invalid role name before POST /roles'); Type guard
function isRolePayload(v) {
return typeof v === 'object' && v !== null && typeof v.name === 'string' && v.name.trim().length > 0;
} Try / catch
try {
await api.createRole({ name });
} catch (e) {
if (e.status === 400 && e.body?.errors?.name) {
// duplicate or invalid name: prompt user for a new one
} else throw e;
} Prevention
- Check GET /roles for name uniqueness before creating
- Trim and require non-empty names in the UI
- Keep role names within the 255-char column limit
When it happens
Trigger: POST /roles with a role name that violates table validation (empty name, name longer than 255 chars, or a rulesChecker uniqueness violation on name).
Common situations: Creating a role whose name already exists (duplicate slug/name), posting an empty or whitespace-only name from a misbehaving client, or importing roles in bulk where one collides with an existing one.
Related errors
- Could not validate resource data.
- Could not validate the password policies settings.
- The role could not be deleted.
- The role could not be updated.
- The role identifier is not valid.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/6e74bbc1fe6e93d6.
Report an issue: GitHub.
Appendix: source
Thrown at src/Service/Roles/RolesAddService.php:64
$data = array_merge($data, [
'description' => null,
'created_by' => $uac->getId(),
'modified_by' => $uac->getId(),
]);
$role = $rolesTable->newEntity($data, ['accessibleFields' => [
'name' => true,
'description' => true,
'created_by' => true,
'modified_by' => true,
]]);
try {
$result = $rolesTable->saveOrFail($role);
} catch (PersistenceFailedException $e) { // @phpstan-ignore-line
$errors = $e->getEntity()->getErrors();
throw new CustomValidationException(
__('The role could not be saved.'),
$errors
);
} catch (Exception $e) {
throw new InternalErrorException(__('Could not save the role, please try again later.'), null, $e);
}
$this->dispatchEvent(self::AFTER_ROLE_CREATE_SUCCESS_EVENT_NAME, [
'uac' => $uac,
'role' => $result,
]);
return $result;
}
}
View on GitHub (pinned to 31c1bbc10f)