flowable/flowable-engine · warning
Could not load image for case diagram creation
Error message
Could not load image for case diagram creation: {} What it means
During static initialization of DefaultCaseDiagramCanvas, the icon PNGs (caseTask.png, processTask.png, decisionTask.png, sendEventTask.png) are loaded from the classpath via ImageIO.read. If any of them cannot be read or found, an IOException is caught and only a warning is logged, leaving the static image fields null. Diagram generation will then produce task nodes without icons or fail later when drawing them.
Solutions
- Verify the flowable-cmmn-image-generator jar contains org/flowable/icons/*.png and that your classloader can load them (unzip -l the jar).
- Disable Maven/Gradle resource filtering on binary files (png) or add nonFilteredFileExtensions for png.
- If using a custom ClassLoader, pass one that can see the flowable jar resources, or null to use the default.
- Check the underlying e.getMessage() in the log: 'Can't read input file' vs 'not found' tells you whether the resource is missing or corrupt.
- Ensure icons are read before any ImageIO Usages are affected: pin a standard flowable release instead of a custom repack.
Example fix
// before (pom.xml resource filtering mangles PNGs) <resource><directory>src/main/resources</directory><filtering>true</filtering></resource> // after <resource><directory>src/main/resources</directory><filtering>false</filtering></resource>
Defensive patterns
Strategy: fallback
Validate before calling
try (var in = getClass().getClassLoader().getResourceAsStream("org/flowable/icons/caseTask.png")) {
if (in == null) throw new IllegalStateException("flowable icon resources missing from classpath");
} Type guard
boolean iconsAvailable(ClassLoader cl) {
return cl.getResource("org/flowable/icons/caseTask.png") != null
&& cl.getResource("org/flowable/icons/processTask.png") != null
&& cl.getResource("org/flowable/icons/decisionTask.png") != null
&& cl.getResource("org/flowable/icons/sendEventTask.png") != null;
} Try / catch
try {
new DefaultCaseDiagramGenerator().generateDiagram(model, imageType, activityFont);
} catch (RuntimeException e) {
LOGGER.warn("Diagram generation unavailable (icons not loadable), skipping diagram", e);
return null; // fallback: proceed without diagram
} Prevention
- Keep png files out of resource filtering in Maven/Gradle builds.
- Verify shaded/fat jars retain org/flowable/icons/* resources (check archive contents in CI).
- Smoke-test diagram generation on the packaged artifact, not just in IDE.
- If using custom classloaders (OSGi, app servers), ensure the flowable image generator bundle can see its own resources.
When it happens
Trigger: Creating a DefaultCaseDiagramCanvas (or generating a CMMN case diagram) when org/flowable/icons/*.png resources are not resolvable through the provided customClassLoader, or the classpath resource is corrupt/unreadable so ImageIO.read throws IOException.
Common situations: Shaded/minified jars or custom classloaders (e.g. OSGi, Spring Boot fat jar with filtering) that exclude or corrupt icon resources; build resource filtering mangling PNG binaries; running with an incomplete flowable-image-generator dependency or repackaged flowable jars missing icon resources.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Could not load image for process diagram creation
- BPMN XSD could not be found
- Cannot read default EL properties
- Class not found
- Class has not been found.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/6b5856f428ef2208.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-image-generator/src/main/java/org/flowable/cmmn/image/impl/DefaultCaseDiagramCanvas.java:211
g.setFont(font);
this.fontMetrics = g.getFontMetrics();
LABEL_FONT = new Font(labelFontName, Font.ITALIC, 10);
ANNOTATION_FONT = new Font(annotationFontName, Font.PLAIN, FONT_SIZE);
try {
TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/timer.png", customClassLoader));
USERLISTENER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/user.png", customClassLoader));
VARIABLELISTENER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/variablelistener.png", customClassLoader));
USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/userTask.png", customClassLoader));
SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/serviceTask.png", customClassLoader));
CASETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/caseTask.png", customClassLoader));
PROCESSTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/processTask.png", customClassLoader));
DECISIONTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/decisionTask.png", customClassLoader));
SENDEVENTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/sendEventTask.png", customClassLoader));
} catch (IOException e) {
LOGGER.warn("Could not load image for case diagram creation: {}", e.getMessage());
}
}
/**
* Generates an image of what currently is drawn on the canvas.
*
* Throws an {@link FlowableImageException} when {@link #close()} is already called.
*/
public InputStream generateImage(String imageType) {
if (closed) {
throw new FlowableImageException("CaseDiagramGenerator already closed");
}
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
ImageIO.write(caseDiagram, imageType, out);
return new ByteArrayInputStream(out.toByteArray());
} catch (IOException e) {
throw new FlowableImageException("Error while generating case image", e);View on GitHub (pinned to d6d39ce1c6)