passbolt/passbolt_api · error · FormValidationException
Could not validate the smtp settings found in database.
Error message
Could not validate the smtp settings found in database.
What it means
Thrown by SmtpSettingsGetSettingsInDbService::getSettings when the SMTP settings stored in the database fail validation against EmailConfigurationForm. Before throwing, the form gets `source: 'database'` appended so diagnostics show which source was invalid; a FormValidationException is raised.
Solutions
- Read the validation errors attached to the FormValidationException; the `source` field will confirm the problem came from the DB record.
- Re-save correct SMTP settings via POST /smtp-settings.json so a valid record replaces the bad one.
- Fix or delete the offending DB row and fall back to file/env configuration temporarily.
- After a passbolt upgrade, re-test SMTP settings since validation rules may have tightened.
Example fix
// before (bad DB record)
{ "sender_email": "not-an-email", "port": "smtp" }
// after: re-save valid settings
POST /smtp-settings.json { "sender_email": "no-reply@mycompany.com", "port": 587, "host": "smtp.mycompany.com", ... } Defensive patterns
Strategy: validation
Validate before calling
$form = new EmailConfigurationForm();
$stored = /* fetch DB row */;
if (!$form->check($stored)) {
// repair or delete the DB row before invoking the get service
} Try / catch
try {
$data = $inDbService->getSettings();
} catch (FormValidationException $e) {
$form = $e->getForm();
Log::error('DB smtp settings invalid, source=' . $form->getData()['source'] ?? 'database');
// fall back to file/env settings
} Prevention
- Only write SMTP settings via the validated API.
- Never edit smtp settings rows manually in SQL.
- Round-trip test (save then read) after passbolt upgrades.
- Delete invalid rows to fall back to file/env config instead of leaving them in place.
When it happens
Trigger: Reading DB-stored SMTP settings (used by the smtp-settings get/test endpoints) where the stored record has invalid values: malformed sender email, out-of-range port, null/empty required fields such as host, or rows written by older versions with different schemas.
Common situations: Settings saved by an older passbolt version that current validation rejects; partial writes; manual DB edits to the smtp_settings/organization_settings record; corrupted records after failed saves.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Could not validate the self registration settings found in…
- Could not validate the smtp settings.
- Client ID should be a valid UUID.
- Could not parse the self registration settings found in…
- Could not validate Duo configuration
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/3324d8bf05d78343.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/SmtpSettings/src/Service/SmtpSettingsGetSettingsInDbService.php:54
* @return array|null
* @throws \App\Error\Exception\FormValidationException if the data does not validate the EmailConfigurationForm
* @throws \Cake\Http\Exception\InternalErrorException if the data in the DB cannot be decrypted
* @throws \Cake\Database\Exception\MissingConnectionException if the database is not in place (this is the case during installation)
*/
public function getSettings(): ?array
{
$form = new EmailConfigurationForm();
$data = $this->readConfigInDB();
if (is_null($data)) {
return null;
}
if (!$form->execute($data)) {
// An exception is thrown, the settings should not be consumed, but the source is appended for
// diagnostic purposes.
$form->set('source', SmtpSettingsGetService::SMTP_SETTINGS_SOURCE_DB);
throw new FormValidationException(__('Could not validate the smtp settings found in database.'), $form);
}
return $form->getData();
}
/**
* Reads SMTP in the organization settings table
*
* @return array|null
* @throws \Cake\Http\Exception\InternalErrorException if the data in the DB cannot be decrypted
*/
protected function readConfigInDB(): ?array
{
/** @var \App\Model\Table\OrganizationSettingsTable $OrganizationSettings */
$OrganizationSettings = TableRegistry::getTableLocator()->get('OrganizationSettings');
try {
$settings = $OrganizationSettings->getByProperty(self::SMTP_SETTINGS_PROPERTY_NAME);
} catch (Throwable $e) {View on GitHub (pinned to 31c1bbc10f)