{"record":{"id":"4aa2e2ec9e51d018","repo":"flowable/flowable-engine","slug":"error-reading-json-value-configuration-4aa2e2","errorCode":null,"errorMessage":"Error reading json value ${configuration}","messagePattern":"Error reading json value (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/jobexecutor/TimerSuspendProcessDefinitionHandler.java","lineNumber":45,"sourceCode":"public class TimerSuspendProcessDefinitionHandler extends TimerChangeProcessDefinitionSuspensionStateJobHandler {\n\n    public static final String TYPE = \"suspend-processdefinition\";\n\n    @Override\n    public String getType() {\n        return TYPE;\n    }\n\n    @Override\n    public void execute(Job job, String configuration, ExecutionEntity execution, CommandContext commandContext) {\n        ProcessEngineConfigurationImpl processEngineConfiguration = commandContext.getProcessEngineConfiguration();\n\n        boolean suspendProcessInstances = false;\n        try {\n            JsonNode configNode = processEngineConfiguration.getObjectMapper().readTree(configuration);\n            suspendProcessInstances = getIncludeProcessInstances(configNode);\n        } catch (Exception e) {\n            throw new FlowableException(\"Error reading json value \" + configuration, e);\n        }\n\n        String processDefinitionId = job.getProcessDefinitionId();\n\n        SuspendProcessDefinitionCmd suspendProcessDefinitionCmd = new SuspendProcessDefinitionCmd(processDefinitionId, null, suspendProcessInstances, null, job.getTenantId());\n        suspendProcessDefinitionCmd.execute(commandContext);\n    }\n\n}\n","sourceCodeStart":27,"sourceCodeEnd":55,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/jobexecutor/TimerSuspendProcessDefinitionHandler.java#L27-L55","documentation":"TimerSuspendProcessDefinitionHandler parses its job handler configuration string as JSON to read the 'includeProcessInstances' flag; if readTree or the flag extraction throws, the handler wraps the failure in FlowableException('Error reading json value ' + configuration). The raw configuration text is embedded in the message to aid diagnosis.","triggerScenarios":"A suspend-process-definition timer job whose JOB_HANDLER_CFG_ column is not valid JSON, or valid JSON lacking the expected includeProcessInstances field that getIncludeProcessInstances requires.","commonSituations":"Jobs written by an older engine version read by a newer one after upgrade (config schema changed); manual edits or data migrations that corrupted the configuration column; copying jobs across environments with mismatched engine versions.","solutions":["Inspect the job's configuration (ACT_RU_JOB.JOB_HANDLER_CFG_) and fix it to the JSON shape the current version expects: {\"includeProcessInstances\":true|false,\"processDefinitionId\":\"...\"} or delete the stale job","Align engine versions: run the upgrade job-cfg migration scripts or ensure all cluster nodes run the same Flowable version","Suspend the definition manually to achieve the intended effect: repositoryService.suspendProcessDefinitionById(id, true, null), then remove the broken job","Recreate the scenario if needed via a fresh ProcessDefinitionSuspension schedule so the engine writes a well-formed configuration"],"exampleFix":"// before: corrupted job config, job keeps failing\n// after: suspend manually and remove the failing job\nrepositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);\nJob job = managementService.createJobQuery().jobId(jobId).singleResult();\nmanagementService.deleteJob(job.getId());","handlingStrategy":"validation","validationCode":"ObjectNode cfg = objectMapper.createObjectNode();\ncfg.put(\"includeProcessInstances\", true);\n// store cfg.toString() as the job handler configuration; verify before firing:\nJsonNode n = objectMapper.readTree(job.getJobHandlerConfiguration());\nif (!n.has(\"includeProcessInstances\")) throw new IllegalStateException(\"malformed suspension job config: \" + job.getJobHandlerConfiguration());","typeGuard":"boolean isValidSuspensionConfig(String cfg) {\n  try {\n    JsonNode n = objectMapper.readTree(cfg);\n    return n != null && n.has(\"includeProcessInstances\") && n.get(\"includeProcessInstances\").isBoolean();\n  } catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n  managementService.executeJob(suspendJobId);\n} catch (FlowableException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Error reading json value\")) {\n    log.error(\"corrupt suspension job cfg: {}\", e.getMessage());\n    managementService.deleteJob(suspendJobId); // or repair cfg then re-execute\n  } else { throw e; }\n}","preventionTips":["Never hand-edit ACT_RU_JOB.JOB_HANDLER_CFG_ contents; recreate jobs through the API instead","Run identical Flowable versions on every cluster node (job config formats differ across versions)","Apply upgrade scripts when migrating so old job configurations are converted","Prefer repositoryService.suspendProcessDefinitionById for one-off suspensions instead of crafting timer jobs manually"],"tags":["json","job-configuration","timer","process-definition-suspension"],"backgroundTag":"json-parse-error","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}