flowable/flowable-engine · error · FlowableException

Error parsing Historic Case Instance Migration Document

Error message

Error parsing Historic Case Instance Migration Document

What it means

HistoricCaseInstanceMigrationDocumentConverter.convertFromJson parses the migration document JSON with Jackson. Any JacksonException (malformed JSON, wrong node types, invalid structure) is wrapped and rethrown as this FlowableException with the Jackson exception as cause.

Solutions

  1. Validate the migration document JSON with a JSON linter/parser before passing it in.
  2. Generate the document programmatically via HistoricCaseInstanceMigrationDocument or the builder API instead of hand-writing JSON.
  3. Inspect the wrapped JacksonException cause for the exact line/problem.
  4. Check property names against the converter's JSON constants (e.g. toCaseDefinitionKey, mappings).

Example fix

// before
String doc = "{ toCaseDefinitionKey: orderCase }"; // unquoted key -> JacksonException
// after
String doc = "{\"toCaseDefinitionKey\":\"orderCase\"}";
Defensive patterns

Strategy: validation

Validate before calling

new ObjectMapper().readTree(migrationJson); // throws JsonProcessingException before engine sees it

Type guard

try { JsonNode n = new ObjectMapper().readTree(json); return n != null && n.isObject(); } catch (JsonProcessingException e) { return false; }

Try / catch

try { document = converter.convertFromJson(jsonStream); } catch (FlowableException e) { if (e.getMessage().equals("Error parsing Historic Case Instance Migration Document")) { log("Bad migration JSON", e.getCause()); } throw e; }

Prevention

When it happens

Trigger: Calling convertFromJson (e.g. when building a migration from a JSON document string/resource) where the JSON is syntactically invalid or contains fields with unexpected types (e.g. mappings where an array or object is expected).

Common situations: Hand-edited migration JSON files; JSON generated with wrong property names so nested structures don't match; passing a non-migration JSON file; encoding/newline corruption in resources.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/HistoricCaseInstanceMigrationDocumentConverter.java:78

    public static HistoricCaseInstanceMigrationDocument convertFromJson(String jsonCaseInstanceMigrationDocument) {

        try {
            JsonNode rootNode = objectMapper.readTree(jsonCaseInstanceMigrationDocument);
            HistoricCaseInstanceMigrationDocumentBuilderImpl documentBuilder = new HistoricCaseInstanceMigrationDocumentBuilderImpl();

            documentBuilder.setCaseDefinitionToMigrateTo(getJsonProperty(TO_CASE_DEFINITION_ID_JSON_PROPERTY, rootNode));
            
            String caseDefinitionKey = getJsonProperty(TO_CASE_DEFINITION_KEY_JSON_PROPERTY, rootNode);
            Integer caseDefinitionVersion = getJsonPropertyAsInteger(TO_CASE_DEFINITION_VERSION_JSON_PROPERTY, rootNode);
            documentBuilder.setCaseDefinitionToMigrateTo(caseDefinitionKey, caseDefinitionVersion);

            documentBuilder.setTenantId(getJsonProperty(TO_CASE_DEFINITION_TENANT_ID_JSON_PROPERTY, rootNode));

            return documentBuilder.build();

        } catch (JacksonException e) {
            throw new FlowableException("Error parsing Historic Case Instance Migration Document", e);
        }

    }
    
    protected static String getJsonProperty(String propertyName, JsonNode jsonNode) {
        if (jsonNode.has(propertyName) && !jsonNode.get(propertyName).isNull()) {
            return jsonNode.get(propertyName).asString();
        }
        
        return null;
    }
    
    protected static Integer getJsonPropertyAsInteger(String propertyName, JsonNode jsonNode) {
        if (jsonNode.has(propertyName) && !jsonNode.get(propertyName).isNull()) {
            return jsonNode.get(propertyName).asInt();
        }
        
        return null;

View on GitHub (pinned to d6d39ce1c6)