flowable/flowable-engine · error · org.activiti.engine.ActivitiException

Couldn't write file

Error message

Couldn't write file ${filePath}

What it means

IoUtil.writeStringToFile writes a string to a classpath-resolved file via BufferedOutputStream. Any exception — including failure resolving the file (see getFile) or an I/O write/flush error — is wrapped in ActivitiException 'Couldn't write file <filePath>' with the original cause chained.

Solutions

  1. Check the chained cause (e.getCause()) to distinguish resolution vs. write failure.
  2. Ensure the target location is a writable directory on the filesystem, not inside a jar.
  3. Grant write permissions to the process user for the target directory.
  4. Use plain java.nio (Files.writeString) with a real filesystem path for non-classpath targets.

Example fix

// before
IoUtil.writeStringToFile(content, "output/result.txt"); // read-only dir
// after
Path target = Paths.get(System.getProperty("java.io.tmpdir"), "result.txt");
Files.writeString(target, content);
Defensive patterns

Strategy: try-catch

Validate before calling

Path dir = Paths.get(outputDir);
if (!Files.isWritable(dir)) throw new IllegalStateException("Not writable: " + dir);

Try / catch

try {
    IoUtil.writeStringToFile(content, path);
} catch (ActivitiException e) {
    if (e.getMessage().startsWith("Couldn't write file")) {
        Throwable c = e.getCause();
        if (c != null && String.valueOf(c.getMessage()).contains("Permission")) { /* fix permissions */ }
    }
}

Prevention

When it happens

Trigger: Calling IoUtil.writeStringToFile(content, filePath) where getFile(filePath) fails (resource not on classpath) or FileOutputStream/write/flush throws (read-only directory, permissions, disk full).

Common situations: Trying to write into a jar or immutable classpath location; read-only deployment directory; missing write permissions for the process user.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/util/IoUtil.java:80

    }

    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.
     */
    public static void closeSilently(InputStream inputStream) {
        try {
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (IOException ignore) {
            // Exception is silently ignored
        }
    }

View on GitHub (pinned to d6d39ce1c6)