flowable/flowable-engine · error · FlowableException

Couldn't read file

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).

Solutions

  1. Check the embedded cause message for the concrete IO error
  2. Verify the file exists on the filesystem (getFile resolves classloader resources — files inside jars are not plain Files)
  3. Fix filesystem permissions on the file/directory
  4. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/1b86d40786230a01. Report an issue: GitHub.

Appendix: 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)