flowable/flowable-engine · error · FlowableException
Error reading json info node for process definition " +…
Error message
Error reading json info node for process definition " + processDefinitionId
What it means
Flowable caches process-definition info (JSON metadata stored via ProcessDefinitionInfoEntity). When the stored info JSON bytes cannot be parsed into an ObjectNode by Jackson, retrieveProcessDefinitionInfoCacheObject wraps the parse failure in a FlowableException naming the process definition. The root cause is corrupt, truncated, or non-JSON bytes behind infoJsonId in the database.
Solutions
- Inspect the ACT_GE_BYTEARRAY row for infoEntity.getInfoJsonId() and verify its bytes are valid JSON (e.g. SELECT and validate with a JSON parser).
- Redeploy the process definition (or re-save the process definition info) so a fresh, valid JSON info node is written and the stale/corrupt blob is replaced.
- Check database charset/encoding settings for the blob column; fix mismatched encoding and re-write the bytes.
- Clear any externally persisted cache and retry after the underlying data is fixed; if parsing was failing due to transient I/O, re-fetching the bytes may succeed.
Example fix
// before (corrupt blob parsed blindly)
byte[] infoBytes = infoEntityManager.findInfoJsonById(infoEntity.getInfoJsonId());
ObjectNode infoNode = (ObjectNode) objectMapper.readTree(infoBytes);
// after (caller-side guard + repair path)
byte[] infoBytes = infoEntityManager.findInfoJsonById(infoEntity.getInfoJsonId());
JsonNode raw = objectMapper.readTree(infoBytes);
if (raw == null || !raw.isObject()) {
// fall back to empty info node and re-publish definition info
cacheObject.setInfoNode(objectMapper.createObjectNode());
} else {
cacheObject.setInfoNode((ObjectNode) raw);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Java: validate blob before use
JsonNode check(byte[] bytes, ObjectMapper om) {
try { return om.readTree(bytes); } catch (Exception e) { return null; }
} Type guard
boolean isValidInfoJson(JsonNode n) { return n != null && n.isObject(); } Try / catch
try {
ObjectNode node = (ObjectNode) objectMapper.readTree(infoBytes);
cacheObject.setInfoNode(node);
} catch (FlowableException e) {
// inspect/repair ACT_GE_BYTEARRAY row or fall back to empty node
cacheObject.setInfoNode(objectMapper.createObjectNode());
} Prevention
- Never hand-edit or partially restore ACT_GE_BYTEARRAY rows; use deployment APIs.
- Validate DB charset/encoding for blob columns during migrations.
- Wrap readTree defensively when consuming blobs of uncertain provenance.
- Re-save process definition info after upgrades or data restores.
When it happens
Trigger: Calling RuntimeService/RepositoryService APIs that resolve process definition info (e.g. getProcessDefinitionInfo) when the ACT_GE_BYTEARRAY row referenced by infoEntity.getInfoJsonId() contains bytes that objectMapper.readTree() cannot parse (corrupt row, manual DB edit, wrong encoding, or a non-JSON blob written by another tool).
Common situations: Manual database manipulation or partial restores of Flowable schema tables (ACT_GE_BYTEARRAY), DB character-set/encoding migrations that mangle BLOB contents, upgrades where info JSON was written by an incompatible serializer, disk/storage corruption behind the blob column.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- Cannot aggregate overview variable
- Cannot aggregate variable
- Cannot convert event payload
- context is null
- Could not deserialize event to json
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/0f3876c831793795.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/deploy/ProcessDefinitionInfoCache.java:148
ProcessDefinitionInfoCacheObject cacheObject = null;
if (cache.containsKey(processDefinitionId)) {
cacheObject = cache.get(processDefinitionId);
} else {
cacheObject = new ProcessDefinitionInfoCacheObject();
cacheObject.setRevision(0);
cacheObject.setInfoNode(objectMapper.createObjectNode());
}
ProcessDefinitionInfoEntity infoEntity = infoEntityManager.findProcessDefinitionInfoByProcessDefinitionId(processDefinitionId);
if (infoEntity != null && infoEntity.getRevision() != cacheObject.getRevision()) {
cacheObject.setRevision(infoEntity.getRevision());
if (infoEntity.getInfoJsonId() != null) {
byte[] infoBytes = infoEntityManager.findInfoJsonById(infoEntity.getInfoJsonId());
try {
ObjectNode infoNode = (ObjectNode) objectMapper.readTree(infoBytes);
cacheObject.setInfoNode(infoNode);
} catch (Exception e) {
throw new FlowableException("Error reading json info node for process definition " + processDefinitionId, e);
}
}
} else if (infoEntity == null) {
cacheObject.setRevision(0);
cacheObject.setInfoNode(objectMapper.createObjectNode());
}
return cacheObject;
}
}
View on GitHub (pinned to d6d39ce1c6)