flowable/flowable-engine · error · FlowableException

Invalid attachment type: " + value.getClass() + " for " +…

Error message

Invalid attachment type: " + value.getClass() + " for " + variableContainer

What it means

Mail attachments supplied via the 'attachments' expression must be of a supported type (String file path, File, ContentItem, or ContentItem[]). addExpressionValueAttachment throws FlowableException when the attachment expression resolves to any other class. The message includes the offending value's class to aid diagnosis.

Solutions

  1. Convert the attachment value to the supported types: String path, java.io.File, ContentItem, or ContentItem[]
  2. If you have a List<ContentItem>, convert with list.toArray(new ContentItem[0]) before assigning
  3. Store binary content as a ContentItem via the content engine rather than byte[] when using mail attachments

Example fix

// before
execution.setVariable("attachments", contentItemList); // List<ContentItem>
// after
execution.setVariable("attachments", contentItemList.toArray(new ContentItem[0]));
Defensive patterns

Strategy: type-guard

Validate before calling

Object att = execution.getVariable("attachments");
boolean ok = att instanceof String || att instanceof java.io.File
    || att instanceof ContentItem || att instanceof ContentItem[];
if (!ok) throw new IllegalArgumentException("Unsupported attachment type: " + att.getClass());

Type guard

boolean isSupportedAttachment(Object v) {
    return v instanceof String || v instanceof java.io.File
        || v instanceof ContentItem || v instanceof ContentItem[];
}

Try / catch

try {
    // mail task with attachments
} catch (FlowableException e) {
    if (e.getMessage().startsWith("Invalid attachment type")) {
        // convert variable to ContentItem[] before retrying
    }
    throw e;
}

Prevention

When it happens

Trigger: The attachments field expression evaluates to an unsupported type, e.g. a byte[], an InputStream, a List<ContentItem> (not an array), a POJO, or a Collection returned by an expression.

Common situations: Passing a java.util.List or List of ContentItem from a variable instead of a ContentItem[] array; passing raw byte[] of file data; passing the wrong variable from a previous service task.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/mail/BaseMailActivityDelegate.java:209

        } else if (value instanceof DataSource dataSource) {
            message.addAttachment(dataSource);

        } else if (value instanceof DataSource[] dataSources) {
            for (DataSource dataSource : dataSources) {
                addExpressionValueAttachment(message, dataSource, variableContainer);
            }

        } else if (value instanceof ContentItem contentItem) {
            message.addAttachment(new ContentItemDataSourceWrapper(contentItem, getContentService()));

        } else if (value instanceof ContentItem[] contentItems) {
            for (ContentItem contentItem : contentItems) {
                addExpressionValueAttachment(message, contentItem, variableContainer);
            }

        } else {
            throw new FlowableException("Invalid attachment type: " + value.getClass() + " for " + variableContainer);
        }

    }

    protected String getStringFromField(Expression expression, V variableContainer) {
        if (expression != null) {
            Object value = expression.getValue(variableContainer);
            if (value != null) {
                return value.toString();
            }
        }
        return null;
    }

    protected Collection<String> parseRecipients(Expression expression, V variableContainer) {
        if (expression == null) {
            return Collections.emptyList();
        }

View on GitHub (pinned to d6d39ce1c6)