flowable/flowable-engine · error · org.activiti.engine.ActivitiException
Couldn't get file
Error message
Couldn't get file ${filePath}: ${e.getMessage()} What it means
IoUtil.getFile resolves a classpath resource URL and converts it to a java.io.File via url.toURI(). Any failure — resource not found (URL null causing NPE), non-file URI schemes like jar:/bundle:, or URISyntaxException — becomes this ActivitiException with the path and cause message.
Solutions
- Confirm the resource exists on the classpath at exactly that path (Class.getResource returns non-null).
- Don't use getFile for resources inside jars — read via getResourceAsStream instead.
- Null-check the URL before conversion and fail with a clearer 'resource not found' message.
- Verify packaging: resources must be exploded directories for File-based access.
Example fix
// before
File f = IoUtil.getFile("templates/app.vm"); // inside a fat jar -> throws
// after
try (InputStream in = IoUtil.class.getClassLoader().getResourceAsStream("templates/app.vm")) {
// read stream instead of File
} Defensive patterns
Strategy: validation
Validate before calling
URL url = IoUtil.class.getClassLoader().getResource(filePath);
if (url == null) throw new IllegalStateException("Classpath resource not found: " + filePath);
if (!"file".equals(url.getProtocol())) throw new IllegalStateException("Resource inside jar, use getResourceAsStream: " + url); Try / catch
try {
File f = IoUtil.getFile(path);
} catch (ActivitiException e) {
if (e.getMessage().startsWith("Couldn't get file")) { /* switch to stream-based loading */ }
} Prevention
- Never use getFile for nested-jar/fat-jar resources — always stream them
- Null-check getResource() result before any File conversion
- Confirm exploded (directory) deployment if File-based access is required
When it happens
Trigger: Calling IoUtil.getFile (directly or via writeStringToFile/readFileAsString/buffer) with a path that isn't a classpath resource, or one packaged inside a jar where the 'jar:' URI cannot be converted to a File.
Common situations: Typo'd resource path; resource not on the classpath; attempting File access on resources inside a Spring Boot fat jar or OSGi bundle.
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
- Cannot read default EL properties
- Couldn't get file
- couldn't open resource stream:
- Couldn't read file
- Couldn't read file
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/6e594b61a6ea3b7f.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/util/IoUtil.java:69
byte[] buffer = new byte[(int) getFile(filePath).length()];
BufferedInputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(getFile(filePath)));
inputStream.read(buffer);
} catch (Exception e) {
throw new ActivitiException("Couldn't read file " + filePath + ": " + e.getMessage());
} finally {
IoUtil.closeSilently(inputStream);
}
return new String(buffer);
}
public static File getFile(String filePath) {
URL url = IoUtil.class.getClassLoader().getResource(filePath);
try {
return new File(url.toURI());
} catch (Exception e) {
throw new ActivitiException("Couldn't get file " + filePath + ": " + e.getMessage());
}
}
public static void writeStringToFile(String content, String filePath) {
BufferedOutputStream outputStream = null;
try {
outputStream = new BufferedOutputStream(new FileOutputStream(getFile(filePath)));
outputStream.write(content.getBytes());
outputStream.flush();
} catch (Exception e) {
throw new ActivitiException("Couldn't write file " + filePath, e);
} finally {
IoUtil.closeSilently(outputStream);
}
}
/**
* Closes the given stream. The same as calling {@link InputStream#close()}, but errors while closing are silently ignored.View on GitHub (pinned to d6d39ce1c6)