flowable/flowable-engine · error · FlowableMailException
header value cannot be null or empty
Error message
header value cannot be null or empty
What it means
In addHeaders, after validating the header name, the client also rejects entries whose value is null or empty, throwing FlowableMailException. A header with no value is not meaningful for mail transport, so the library refuses to add it rather than sending a malformed message.
Source
Thrown at modules/flowable-mail/src/main/java/org/flowable/mail/common/impl/jakarta/mail/JakartaMailFlowableMailClient.java:155
} else {
message.setSubject(subject);
}
}
}
protected void addHeaders(MimeMessage message, Map<String, String> headers, Charset charset) throws MessagingException {
if (headers != null && !headers.isEmpty()) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
String name = entry.getKey();
String value = entry.getValue();
if (StringUtils.isEmpty(name)) {
throw new FlowableMailException("header name cannot be null or empty");
}
if (StringUtils.isEmpty(value)) {
throw new FlowableMailException("header value cannot be null or empty");
}
String foldedHeaderValue = createFoldedHeaderValue(name, value, charset);
message.addHeader(name, foldedHeaderValue);
}
}
}
protected String createFoldedHeaderValue(String name, String value, Charset charset) {
try {
return MimeUtility.fold(name.length() + 2, MimeUtility.encodeText(value, charset != null ? charset.name() : null, null));
} catch (UnsupportedEncodingException e) {
return value;
}
}
protected void addTo(MimeMessage message, Collection<String> to) {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Remove or skip header entries with null/empty values before constructing the request.
- Provide a real default value for optional headers instead of an empty string.
- Validate the headers map in application code before sending.
Example fix
// before
headers.put("X-Campaign", campaignId); // campaignId may be ""
// after
if (campaignId != null && !campaignId.isEmpty()) {
headers.put("X-Campaign", campaignId);
} Defensive patterns
Strategy: validation
Validate before calling
Map<String,String> safeHeaders = headers.entrySet().stream()
.filter(e -> e.getValue() != null && !e.getValue().trim().isEmpty())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); Type guard
boolean hasValuedHeaders(Map<String,String> h) { return h.values().stream().allMatch(v -> v != null && !v.isBlank()); } Try / catch
try { client.sendMail(request); } catch (FlowableMailException e) { if (e.getMessage().contains("header value")) { log.warn("empty header value in request"); } throw e; } Prevention
- Skip optional headers entirely instead of setting them to empty strings.
- Provide default values for template-substituted header content.
- Validate header maps in a shared mail-request builder.
When it happens
Trigger: Passing a SendMailRequest whose extraHeaders map contains an entry with an empty-string or null value, e.g. headers where the value was optional and defaulted to nothing.
Common situations: Building headers from configuration where the value key is missing; templates that substitute empty variables into header values; empty tracking or metadata headers produced by upstream systems.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- header name cannot be null or empty
- Failed to create mime message
- Could not add as recipient
- Invalid email
- Could not set as from address in email
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/c7d1bc666c3487b3.
Report an issue: GitHub.