flowable/flowable-engine · error · FlowableException
Couldn't read file ${filePath}: ${e.getMessage()}
Error message
Couldn't read file ${filePath}: ${e.getMessage()} What it means
IoUtil.readFileAsString reads a whole file into a String and wraps any exception in FlowableException 'Couldn't read file <path>: <message>'. Note it first calls getFile(path), so a file that cannot be located via the classloader fails earlier in getFile (error 1819).
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/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 FlowableException("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 FlowableException("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 FlowableException("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)
Solutions
- Check the embedded cause message for the concrete IO error
- Verify the file exists on the filesystem (getFile resolves classloader resources — files inside jars are not plain Files)
- Fix filesystem permissions on the file/directory
- Prefer getResourceAsStream-based reading for classpath resources inside archives
Example fix
// before
String content = IoUtil.readFileAsString("config/process.xml");
// after
try (InputStream in = getClass().getClassLoader().getResourceAsStream("config/process.xml")) {
String content = IoUtil.readInputStream(in, "config/process.xml").toString();
} Defensive patterns
Strategy: try-catch
Validate before calling
File f = new File(filePath);
if (!f.isFile() || !f.canRead()) {
throw new IllegalStateException("Cannot read file: " + filePath);
} Try / catch
try {
String content = IoUtil.readFileAsString(filePath);
} catch (FlowableException e) {
logger.error("File read failed for {}: {}", filePath, e.getMessage());
} Prevention
- Confirm the file is on the real filesystem, not inside a jar (use getResourceAsStream otherwise)
- Check read permissions after deployments/container builds
- Don't assume classpath-relative paths map to disk files
When it happens
Trigger: Calling IoUtil.readFileAsString for a path that resolves via classloader but cannot be opened/read: unreadable permissions, file removed between lookup and read, or IO error during read.
Common situations: Reading config/resource files bundled with the app; files inside jars/WARs where File-based access breaks; permission changes in containerized deployments.
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
- Cannot read default EL properties
- Couldn't get file ${filePath}: ${e.getMessage()}
- resource '${resource}' doesn't exist
- couldn't open resource stream:
- couldn't open resource stream: ${message}
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/1b86d40786230a01.
Report an issue: GitHub.