SonarSource/sonarqube · error · NotFoundException
Email configuration doesn't exist.
Error message
Email configuration doesn't exist.
What it means
Thrown by EmailConfigurationService when the single email configuration has not been created yet: configurationExists() checks the EMAIL_CONFIG_SMTP_HOST internal property and finds it empty. getConfiguration, updateConfiguration and deleteConfiguration all call this guard and fail with NotFoundException because there is nothing to read/update/delete.
Solutions
- Call the create/POST endpoint to create the configuration before updating or reading it
- Check existence first (GET and handle 404) then create-if-absent, update-if-present
- Verify internal property sonar.email.* (SMTP host) exists in the DB if you believe config existed — it may have been wiped
Example fix
// before
service.updateConfiguration("default", newCfg); // 404 if never created
// after
try { service.getConfiguration("default"); service.updateConfiguration("default", newCfg); }
catch (NotFoundException e) { service.createConfiguration(newCfg); } Defensive patterns
Strategy: try-catch
Validate before calling
// create-if-missing before update
boolean exists;
try { client.getEmailConfiguration(id); exists = true; }
catch (NotFoundException e) { exists = false; }
if (!exists) client.createEmailConfiguration(cfg); else client.updateEmailConfiguration(id, cfg); Try / catch
try {
service.updateConfiguration(id, cfg);
} catch (NotFoundException e) {
// configuration never created — create it instead
service.createConfiguration(cfg);
} Prevention
- On fresh installs, create email config before attempting updates
- Use create-or-update (upsert) wrappers around singleton config APIs
- After restores/backups, verify sonar.email SMTP properties exist
When it happens
Trigger: GET/PUT/DELETE email configuration before any email SMTP settings were ever saved (no SMTP host stored in internal properties); after settings were deleted; on a fresh SonarQube install.
Common situations: Automation tries to update SMTP settings on a new instance without creating them first; UI/API race where a delete completed before a subsequent update; instance restored from a backup lacking internal properties.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Email configuration with id
- Unknown type of SMTP secure connection:
- Unknown type of SMTP secure connection:
- Fail to decrypt the property
- Failed to send quality gate change email notification for…
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/95060e20ee0e636f.
Report an issue: GitHub.
Appendix: source
Thrown at server/sonar-webserver-common/src/main/java/org/sonar/server/common/email/config/EmailConfigurationService.java:268
return existingConfig.authMethod().equals(EmailConfigurationAuthMethod.OAUTH);
}
private static boolean isRequestParameterDefined(@Nullable NonNullUpdatedValue<?> parameter) {
return parameter != null && parameter.isDefined();
}
public void deleteConfiguration(String id) {
throwIfNotUniqueConfigurationId(id);
try (DbSession dbSession = dbClient.openSession(false)) {
throwIfConfigurationDoesntExist(dbSession);
EMAIL_CONFIGURATION_PROPERTIES.forEach(propertyKey -> dbClient.internalPropertiesDao().delete(dbSession, propertyKey));
dbSession.commit();
}
}
private void throwIfConfigurationDoesntExist(DbSession dbSession) {
if (!configurationExists(dbSession)) {
throw new NotFoundException("Email configuration doesn't exist.");
}
}
private boolean configurationExists(DbSession dbSession) {
String property = getStringInternalPropertyOrEmpty(dbSession, EMAIL_CONFIG_SMTP_HOST);
return StringUtils.isNotEmpty(property);
}
private void setInternalIfDefined(DbSession dbSession, String propertyKey, @Nullable UpdatedValue<String> value) {
if (value != null) {
value.applyIfDefined(propertyValue -> setInternalProperty(dbSession, propertyKey, propertyValue));
}
}
private void setInternalProperty(DbSession dbSession, String propertyKey, @Nullable String value) {
if (StringUtils.isNotEmpty(value)) {
dbClient.internalPropertiesDao().save(dbSession, propertyKey, value);
} else {View on GitHub (pinned to 184c821202)