flowable/flowable-engine · error · FlowableException

Failed to read resource ${resource}

Error message

Failed to read resource ${resource}

What it means

If reading the classpath resource stream raises an IOException while opening or closing it, addClasspathResource() wraps the IOException in FlowableException("Failed to read resource ..."). Note that the 'not found' FlowableException from the try block is not an IOException and propagates unchanged; this message specifically means an I/O problem, and its cause holds the details.

Source

Thrown at modules/flowable-app-engine/src/main/java/org/flowable/app/engine/impl/repository/AppDeploymentBuilderImpl.java:82

        AppResourceEntity resource = resourceEntityManager.create();
        resource.setName(resourceName);
        resource.setBytes(bytes);
        deployment.addResource(resource);
        return this;
    }

    @Override
    public AppDeploymentBuilder addClasspathResource(String resource) {
        try (final InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource)) {
            if (inputStream == null) {
                throw new FlowableException("resource '" + resource + "' not found");
            }
            
            return addInputStream(resource, inputStream);
            
        } catch (IOException ex) {
            throw new FlowableException("Failed to read resource " + resource, ex);
        }
    }

    @Override
    public AppDeploymentBuilder addString(String resourceName, String text) {
        if (text == null) {
            throw new FlowableException("text is null");
        }

        AppResourceEntity resource = resourceEntityManager.create();
        resource.setName(resourceName);
        resource.setBytes(text.getBytes(StandardCharsets.UTF_8));
        deployment.addResource(resource);
        return this;
    }
    
    @Override
    public AppDeploymentBuilder addBytes(String resourceName, byte[] bytes) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Inspect the cause chain of the FlowableException to find the underlying IOException source.
  2. Rebuild/re-download the artifact — a corrupted jar is the most common root cause.
  3. Extract the resource to the filesystem at startup and deploy from a FileInputStream instead of reading it through the classloader.
  4. Check for a security manager or custom classloader interfering with resource reads.

Example fix

// before
deploymentBuilder.addClasspathResource("apps/myApp.bar"); // IOException from corrupted jar

// after
byte[] data = Files.readAllBytes(Paths.get("conf/apps/myApp.bar")); // read from filesystem
deploymentBuilder.addInputStream("myApp.bar", new ByteArrayInputStream(data));
Defensive patterns

Strategy: try-catch

Validate before calling

try (InputStream test = getClass().getClassLoader().getResourceAsStream(resource)) { if (test == null || test.read() == -1) { throw new IllegalStateException("Resource unreadable or empty: " + resource); } }

Try / catch

try { deploymentBuilder.addClasspathResource(resource); } catch (FlowableException e) { log.error("Reading resource {} failed: {}", resource, e.getCause(), e); }

Prevention

When it happens

Trigger: The try-with-resources block in addClasspathResource fails with IOException — typically when closing a stream backed by a jar/zip entry that is corrupted, or when a custom classloader throws while reading the resource.

Common situations: Corrupted jars in the classpath; resources inside nested jars handled by custom classloaders; JVM-level I/O problems (disk errors, security managers blocking reads); fat-jar packaging issues where entries cannot be reopened.

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/7a5d19b23702d3bc. Report an issue: GitHub.