flowable/flowable-engine · error · FlowableImageException
CaseDiagramGenerator already closed
Error message
CaseDiagramGenerator already closed
What it means
DefaultCaseDiagramCanvas implements AutoCloseable; after close() is called the internal BufferedImage and state are disposed, so generateImage cannot render. The canvas is a single-shot generator: generate then close, never the reverse order.
Solutions
- Call generateImage() before close(); do not reuse the canvas after closing
- Create a new DefaultCaseDiagramCanvas (via CaseDiagramGenerator) for each export
- Restructure try-with-resources so all generateImage calls happen inside the block
- If multiple formats are needed, call generateImage once per format before closing
Example fix
// before
try (DefaultCaseDiagramCanvas canvas = ...) { }
InputStream is = canvas.generateImage("png");
// after
try (DefaultCaseDiagramCanvas canvas = ...) {
InputStream is = canvas.generateImage("png");
} Defensive patterns
Strategy: try-catch
Validate before calling
if (canvas.isClosed()) { canvas = createNewCanvas(caseDefinition); } Type guard
boolean usable(DefaultCaseDiagramCanvas c) { return !c.isClosed(); } Try / catch
try {
InputStream is = canvas.generateImage("png");
} catch (FlowableImageException e) {
canvas = recreateCanvas();
InputStream is = canvas.generateImage("png");
} Prevention
- Generate images strictly before close()
- Use try-with-resources with all generation inside the block
- Create a new canvas per export instead of caching instances
When it happens
Trigger: Calling generateImage(String imageType) on a DefaultCaseDiagramCanvas instance after close() has already been invoked; reusing one canvas to export the diagram multiple times after the first close.
Common situations: try-with-resources closing the canvas then a later attempt to re-export; caching a canvas for repeated PNG/SVG exports; code that closes in a finally block but still calls generateImage afterwards.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- CaseDiagramGenerator already closed
- DecisionRequirementsDiagramGenerator already closed
- Can only disable a plan item instance which is in state…
- Can only enable a plan item instance which is in state…
- Can only trigger a plan item that is in the ACTIVE state
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/cd907a5d61c52e05.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-image-generator/src/main/java/org/flowable/cmmn/image/impl/DefaultCaseDiagramCanvas.java:222
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);
}
}
/**
* Generates an image of what currently is drawn on the canvas.
*
* Throws an {@link FlowableImageException} when {@link #close()} is already called.
*/
public BufferedImage generateBufferedImage(String imageType) {
if (closed) {
throw new FlowableImageException("CaseDiagramGenerator already closed");View on GitHub (pinned to d6d39ce1c6)