flowable/flowable-engine · error · FlowableIllegalArgumentException
text is null
Error message
text is null
What it means
Flowable's DeploymentBuilder.addString attaches an in-memory String as a deployment resource. The API rejects a null text argument with a FlowableIllegalArgumentException because a resource with no content cannot be stored. The content may be null because the caller passed a null literal or an unresolved variable.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/repository/DeploymentBuilderImpl.java:93
@Override
public DeploymentBuilder addClasspathResource(String resource) {
try (final InputStream inputStream = ReflectUtil.getResourceAsStream(resource)) {
if (inputStream == null) {
throw new FlowableIllegalArgumentException("resource '" + resource + "' not found");
}
return addInputStream(resource, inputStream);
} catch (IOException ex) {
throw new FlowableException("Failed to read resource " + resource, ex);
}
}
@Override
public DeploymentBuilder addString(String resourceName, String text) {
if (text == null) {
throw new FlowableIllegalArgumentException("text is null");
}
ResourceEntity resource = resourceEntityManager.create();
resource.setName(resourceName);
resource.setBytes(text.getBytes(StandardCharsets.UTF_8));
deployment.addResource(resource);
return this;
}
@Override
public DeploymentBuilder addBytes(String resourceName, byte[] bytes) {
if (bytes == null) {
throw new FlowableIllegalArgumentException("bytes is null");
}
ResourceEntity resource = resourceEntityManager.create();
resource.setName(resourceName);
resource.setBytes(bytes);
deployment.addResource(resource);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure the String passed to addString is non-null before calling; check the variable that produces it.
- If using addBpmnModel, verify the BpmnModel contains at least one process so XML conversion yields content.
- Use addString(resourceName, text == null ? "" : text) only if an empty resource is acceptable; otherwise treat null as a bug.
- Log the resource name and producer of the text to find where null originates.
Example fix
// before
String bpmnXml = config.getBpmnXml(); // may be null
repositoryService.createDeployment().addString("proc.bpmn20.xml", bpmnXml).deploy();
// after
String bpmnXml = config.getBpmnXml();
if (bpmnXml == null || bpmnXml.isEmpty()) {
throw new IllegalStateException("bpmnXml is not configured");
}
repositoryService.createDeployment().addString("proc.bpmn20.xml", bpmnXml).deploy(); Defensive patterns
Strategy: validation
Validate before calling
if (text == null || text.isEmpty()) throw new IllegalArgumentException("resource text for " + resourceName + " is empty"); Type guard
boolean hasText(String s) { return s != null && !s.trim().isEmpty(); } Try / catch
try {
builder.addString(name, text).deploy();
} catch (FlowableIllegalArgumentException e) {
log.error("addString rejected input: {}", e.getMessage());
throw e;
} Prevention
- Null-check strings produced by config or model serialization before adding them as resources.
- Prefer addInputStream/addBytes with content you have verified.
- Write a test that deploys every programmatically generated resource.
- Never pass Optional.get-less or possibly-null variables directly into the builder.
When it happens
Trigger: Calling deploymentBuilder.addString(resourceName, null); addBpmnModel internally converts the model to XML and calls addString, so a model that serializes to null text also triggers it; passing a String variable that was never initialized.
Common situations: Programmatic model creation where BpmnModel conversion produced no output; refactoring that removed the string constant; configuration property expected to hold the XML but was null; NPE-avoiding wrappers that pass null through.
Related errors
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/3dbb0d6a75fc645a.
Report an issue: GitHub.