quarkusio/quarkus · error · IllegalArgumentException
An attachment must contain either a file or a raw data
Error message
An attachment must contain either a file or a raw data
What it means
The Quarkus mailer refuses to build a mail attachment whose content is ambiguous or missing. An attachment must carry exactly one content source: a file on disk OR raw byte data, never both and never neither. MutinyMailerImpl.toMailAttachment validates this before converting the MailAttachment to a Vert.x attachment stream and throws IllegalArgumentException immediately when the rule is violated.
Source
Thrown at extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MutinyMailerImpl.java:274
private MultiMap toMultimap(Map<String, List<String>> headers) {
MultiMap mm = MultiMap.caseInsensitiveMultiMap();
headers.forEach(mm::add);
return mm;
}
private Uni<MailAttachment> toMailAttachment(Attachment attachment) {
MailAttachment attach = MailAttachment.create();
attach.setName(attachment.getName());
attach.setContentId(attachment.getContentId());
attach.setDescription(attachment.getDescription());
attach.setDisposition(attachment.getDisposition());
attach.setContentType(attachment.getContentType());
if ((attachment.getFile() == null && attachment.getData() == null) // No content
|| (attachment.getFile() != null && attachment.getData() != null)) // Too much content
{
throw new IllegalArgumentException("An attachment must contain either a file or a raw data");
}
return getAttachmentStream(vertx, attachment)
.onItem().transform(attach::setData);
}
private Recipients filterApprovedRecipients(List<String> emails) {
if (approvedRecipients.isEmpty()) {
return new Recipients(emails, List.of());
}
List<String> allowedRecipients = new ArrayList<>();
List<String> rejectedRecipients = new ArrayList<>();
emailLoop: for (String email : emails) {
for (Pattern approvedRecipient : approvedRecipients) {
if (approvedRecipient.matcher(email).matches()) {
allowedRecipients.add(email);View on GitHub (pinned to e1c734241f)
Solutions
- Ensure each MailAttachment has exactly one content source: set either file(...) or data(...), never both
- If you have bytes, use MailAttachment.builder().data(bytes) and do not also call file(...); if you have a path, use file(...) only
- Before sending, check attachment.getFile() == null ^ attachment.getData() != null and skip or fix invalid attachments
- If the attachment is built conditionally, add a guard that falls back to an empty/placeholder attachment when no content was produced
Example fix
// before
MailAttachment att = MailAttachment.builder()
.fileName("report.pdf")
.file(path)
.data(bytes) // both file and data set -> throws
.build();
// after
MailAttachment att = MailAttachment.builder()
.fileName("report.pdf")
.data(bytes)
.build(); Defensive patterns
Strategy: validation
Validate before calling
if ((att.getFile() == null && att.getData() == null) || (att.getFile() != null && att.getData() != null)) {
throw new IllegalArgumentException("Attachment must have exactly one of file or data: " + att.getName());
} Type guard
static boolean hasExactlyOneContent(MailAttachment a) {
return (a.getFile() == null) ^ (a.getData() == null);
} Try / catch
try {
mailer.send(mail.addAttachment(att));
} catch (IllegalArgumentException e) {
log.errorf("Invalid mail attachment: %s", e.getMessage());
} Prevention
- Use MailAttachment.builder() and set only one of file()/data() per attachment
- Add a unit test asserting every attachment your code produces passes hasExactlyOneContent
- When converting uploads, null out the source file path after reading bytes into data
When it happens
Trigger: Calling any mailer send method with a MailAttachment where both getFile() and getData() are null (no content set), or where both are non-null (file and data set simultaneously). Typically caused by building a MailAttachment via builder without calling either file(...) or data(...), or setting data programmatically while file(...) was already set.
Common situations: Building attachments dynamically from uploaded bytes and forgetting to clear the source file path; conditional code where neither branch executed so the builder produced an empty attachment; loading file bytes into data but leaving the file field populated; deserializing attachment config from JSON where only one field was expected but both were present.
Related errors
- Cannot add header, key and value must not be null
- Cannot remove header, key must not be null
- The `mails` parameter must not be `null`
- Unable to send an email
- Unable to send an email, an email address is invalid
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/a379466b3ad183f5.
Report an issue: GitHub.