flowable/flowable-engine · error · org.activiti.engine.ActivitiException
Couldn't read file
Error message
Couldn't read file ${filePath}: ${e.getMessage()} What it means
IoUtil.readFileAsString loads a classpath-relative file into a String via a BufferedInputStream. Any failure opening or reading the file (missing file, permission, IO error) is rethrown as ActivitiException including the file path and the cause's message.
Solutions
- Verify the file exists at the exact classpath-relative path (check spelling and case).
- Include the resource in the build (src/main/resources).
- For resources inside jars, read via ClassLoader.getResourceAsStream instead of File.
- Check file permissions on the target resource.
Example fix
// before
String content = IoUtil.readFileAsString("config/app.properties"); // not packaged
// after (move file to src/main/resources/config/app.properties) or read via stream:
try (InputStream in = IoUtil.class.getClassLoader().getResourceAsStream("config/app.properties")) {
String content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
} Defensive patterns
Strategy: validation
Validate before calling
URL url = IoUtil.class.getClassLoader().getResource(filePath);
if (url == null) throw new IllegalStateException("Resource not on classpath: " + filePath);
if (!"file".equals(url.getProtocol())) throw new IllegalStateException("Resource is not file-accessible: " + url); Try / catch
try {
String s = IoUtil.readFileAsString(path);
} catch (ActivitiException e) {
if (e.getMessage().startsWith("Couldn't read file")) { /* fall back to classpath stream */ }
} Prevention
- Verify resources are packaged in src/main/resources and included in the artifact
- Match case exactly — classpath lookups are case-sensitive on Linux
- Prefer getResourceAsStream over File-based access for portable resource loading
When it happens
Trigger: Calling IoUtil.readFileAsString(filePath) where the resource resolves on the classpath but FileInputStream fails — file absent at that location, is a directory, or is unreadable.
Common situations: Resources not packaged in the artifact (missing from src/main/resources); case-sensitive classpath mismatches on Linux; reading files inside nested jars which File-based access cannot handle.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Couldn't get file
- Cannot read default EL properties
- Couldn't get file
- couldn't open resource stream:
- Couldn't read file
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/7ef69c322254e3cd.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/util/IoUtil.java:57
int bytesRead = inputStream.read(buffer);
while (bytesRead != -1) {
outputStream.write(buffer, 0, bytesRead);
bytesRead = inputStream.read(buffer);
}
} catch (Exception e) {
throw new ActivitiException("couldn't read input stream " + inputStreamName, e);
}
return outputStream.toByteArray();
}
public static String readFileAsString(String filePath) {
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 {View on GitHub (pinned to d6d39ce1c6)