flowable/flowable-engine · error · FlowableException
byte array for resource '${resourceName}' is null
Error message
byte array for resource '${resourceName}' is null What it means
After reading the InputStream, addInputStream checks that the produced byte array is not null and throws FlowableException if it is. IOUtils.toByteArray never returns null on success, so reaching this check indicates an exotic/null-returning stream wrapper or a defensive guard against empty/invalid stream implementations. The resource cannot be added to the DMN deployment without bytes.
Source
Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/repository/DmnDeploymentBuilderImpl.java:68
this.deployment = dmnEngineConfiguration.getDeploymentEntityManager().create();
this.resourceEntityManager = dmnEngineConfiguration.getResourceEntityManager();
}
@Override
public DmnDeploymentBuilder addInputStream(String resourceName, InputStream inputStream) {
if (inputStream == null) {
throw new FlowableException("inputStream for resource '" + resourceName + "' is null");
}
byte[] bytes = null;
try {
bytes = IOUtils.toByteArray(inputStream);
} catch (Exception e) {
throw new FlowableException("could not get byte array from resource '" + resourceName + "'", e);
}
if (bytes == null) {
throw new FlowableException("byte array for resource '" + resourceName + "' is null");
}
DmnResourceEntity resource = resourceEntityManager.create();
resource.setName(resourceName);
resource.setBytes(bytes);
deployment.addResource(resource);
return this;
}
@Override
public DmnDeploymentBuilder 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) {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Replace the custom/wrapper InputStream with a standard one: new ByteArrayInputStream(byteArray) or FileInputStream/Files.newInputStream.
- If you hold the content already, use builder.addInputStream(name, new ByteArrayInputStream(bytes)) after verifying bytes != null.
- Check that no test mock is leaking into production code paths; restore the real resource source.
- Log/inspect the stream class to find which non-standard implementation returns null and fix its read() contract.
Example fix
// before
InputStream is = myCustomStreamWrapper.getStream(); // returns null bytes
builder.addInputStream("decision.dmn", is);
// after
byte[] bytes = Files.readAllBytes(Paths.get("src/main/resources/decision.dmn"));
builder.addInputStream("decision.dmn", new ByteArrayInputStream(bytes)); Defensive patterns
Strategy: type-guard
Validate before calling
byte[] bytes = readSourceBytes();
if (bytes == null || bytes.length == 0) {
throw new IllegalArgumentException("Resource content is empty/null: " + resourceName);
}
builder.addInputStream(resourceName, new ByteArrayInputStream(bytes)); Type guard
boolean isValidStream(InputStream is) {
return is != null && !(is instanceof NullInputStream);
} Try / catch
try {
builder.addInputStream(name, is);
} catch (FlowableException e) {
if (e.getMessage().startsWith("byte array for resource")) {
// stream implementation returned null bytes; rebuild from a standard stream
} else { throw e; }
} Prevention
- Use only standard InputStream implementations (ByteArrayInputStream, FileInputStream, ClassLoader streams).
- Do not let test mocks or placeholder streams reach the deployment builder.
- Buffer content to byte[] yourself and validate before adding resources.
- Keep custom stream wrappers conforming to the InputStream contract.
When it happens
Trigger: Calling addInputStream(name, is) with a non-null but degenerate InputStream implementation whose read path yields a null byte array (custom or mocking stream), or a wrapper that returns null content. Practically rare — most real failures hit the earlier 'could not get byte array' error instead.
Common situations: Custom InputStream subclasses or test doubles that violate the InputStream contract; framework-provided stream wrappers returning null bytes; passing a placeholder stream from uninitialized code under test.
Related errors
- Required decision <decisionId> is not available
- deploymentId is null
- deployment does not exist: <deploymentId>
- Could not find deployment with id <deploymentId>
- Could not find deployment with id <deploymentId>
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/c20572991b24d692.
Report an issue: GitHub.