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

  1. Remove or skip header entries with null/empty values before constructing the request.
  2. Provide a real default value for optional headers instead of an empty string.
  3. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/c7d1bc666c3487b3. Report an issue: GitHub.