{"record":{"id":"3051e23259407d7e","repo":"flowable/flowable-engine","slug":"programmatic-error-unsupported-transition-trans","errorCode":null,"errorMessage":"Programmatic error: unsupported transition ${transition} for ${planItemInstanceEntity}","messagePattern":"Programmatic error: unsupported transition (.+?) for (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/job/AsyncLeaveActivePlanItemInstanceJobHandler.java","lineNumber":82,"sourceCode":"                    CommandContextUtil.getAgenda(commandContext).planExitPlanItemInstanceOperation(planItemInstanceEntity, exitCriterionId, exitType, exitEventType);\n\n                } else if (PlanItemTransition.TERMINATE.equals(transition)) {\n                    String exitType = jsonConfiguration.path(OperationSerializationMetadata.FIELD_EXIT_TYPE).stringValue(null);\n                    String exitEventType = jsonConfiguration.path(OperationSerializationMetadata.FIELD_EXIT_EVENT_TYPE).stringValue(null);\n                    CommandContextUtil.getAgenda(commandContext).planTerminatePlanItemInstanceOperation(planItemInstanceEntity, exitType, exitEventType);\n\n                } else if (PlanItemTransition.FAULT.equals(transition)) {\n                    String errorCode = jsonConfiguration.path(OperationSerializationMetadata.FIELD_ERROR_CODE).stringValue(null);\n                    if (errorCode != null) {\n                        String errorMessage = jsonConfiguration.path(OperationSerializationMetadata.FIELD_ERROR_MESSAGE).stringValue(null);\n                        CmmnFault reconstructedError = errorMessage != null ? new CmmnFault(errorCode, errorMessage) : new CmmnFault(errorCode);\n                        CommandContextUtil.getAgenda(commandContext).planFailPlanItemInstanceOperation(planItemInstanceEntity, reconstructedError);\n                    } else {\n                        CommandContextUtil.getAgenda(commandContext).planFailPlanItemInstanceOperation(planItemInstanceEntity);\n                    }\n\n                } else {\n                    throw new FlowableException(\"Programmatic error: unsupported transition \" + transition + \" for \" + planItemInstanceEntity);\n\n                }\n\n            } catch (Exception e) {\n                throw new FlowableException(\"Could not deserialize job configuration\", e);\n            }\n\n        } else {\n            throw new FlowableException(\"Invalid usage of \" + TYPE + \" job handler, variable scope is of type \" + variableScope.getClass());\n        }\n    }\n\n}\n","sourceCodeStart":64,"sourceCodeEnd":96,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/job/AsyncLeaveActivePlanItemInstanceJobHandler.java#L64-L96","documentation":"AsyncLeaveActivePlanItemInstanceJobHandler replays a plan item transition (stored in the job configuration) asynchronously. It only supports a fixed set of transition values (e.g. complete, terminate, fail, exit); anything else reaches the else branch and throws. This is a programming/configuration error: the serialized transition string in the job is not one the handler knows how to plan an operation for.","triggerScenarios":"execute(job, caseInstanceId, variableScope, commandContext) deserializes the job configuration into a transition string and it is not one of the supported values (complete/terminate/fail/exit); the planFail branch is only entered for failure conditions, and all other unrecognized values fall through to the throw.","commonSituations":"Job configuration was hand-edited or produced by a different Flowable version writing transition names this build does not understand; a custom command serialized an arbitrary transition into the job configuration; deserialization yields an unexpected value after an upgrade.","solutions":["Inspect the job's configuration (ACT_RU_JOB CONFIG_ column) and confirm the serialized transition name matches one supported by this handler version.","Upgrade or align the Flowable version of the engine writing the job with the engine executing it, so both agree on transition names.","If you produce these jobs with custom code, only pass supported transition values (complete, terminate, fail, exit).","Check the deserialization code path for corruption — the surrounding catch wraps deserialization in 'Could not deserialize job configuration', so a corrupted config may masquerade as an unsupported transition."],"exampleFix":"// before\ncmmnRuntimeService.completePlanItemInstance(planItemInstanceId); // wrong API writing custom transition\n// after\n// use only supported transition triggers that schedule async leave operations\nPlanItemInstance pii = cmmnRuntimeService.createPlanItemInstanceQuery().planItemInstanceId(id).singleResult();\ncmmnRuntimeService.completePlanItemInstance(pii.getId());","handlingStrategy":"validation","validationCode":"Set<String> supported = Set.of(\"complete\",\"terminate\",\"fail\",\"exit\");\nif (!supported.contains(transition)) throw new IllegalArgumentException(\"Unsupported transition: \" + transition);","typeGuard":null,"tryCatchPattern":"try {\n    // trigger plan item transition via runtime API\n} catch (FlowableException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Programmatic error: unsupported transition\")) {\n        // inspect job config / upgrade engine, do not blind-retry\n        throw new ConfigurationException(\"Invalid async leave transition\", e);\n    }\n    throw e;\n}","preventionTips":["Only use supported public runtime APIs (complete/terminate/fail plan item) to trigger async leave jobs","Keep all Flowable nodes on the same version so transition names match","Never hand-edit job configuration columns","Add a test asserting the job config serialization round-trips"],"tags":["flowable","cmmn","async-job","plan-item","state-transition"],"backgroundTag":"unsupported-enum-value","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"}