{"record":{"id":"c7cde5ab93ef516b","repo":"flowable/flowable-engine","slug":"formkey-expression-does-not-resolve-to-a-string-c7cde5","errorCode":null,"errorMessage":"FormKey expression does not resolve to a string: %s","messagePattern":"FormKey expression does not resolve to a string: (.+?)","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java","lineNumber":206,"sourceCode":"        if (activeCategoryExpression != null) {\n            final Object category = activeCategoryExpression.getValue(execution);\n            if (category != null) {\n                if (category instanceof String) {\n                    task.setCategory((String) category);\n                } else {\n                    throw new ActivitiIllegalArgumentException(\"Category expression does not resolve to a string: \" +\n                            activeCategoryExpression.getExpressionText());\n                }\n            }\n        }\n\n        if (activeFormKeyExpression != null) {\n            final Object formKey = activeFormKeyExpression.getValue(execution);\n            if (formKey != null) {\n                if (formKey instanceof String) {\n                    task.setFormKey((String) formKey);\n                } else {\n                    throw new ActivitiIllegalArgumentException(\"FormKey expression does not resolve to a string: \" +\n                            activeFormKeyExpression.getExpressionText());\n                }\n            }\n        }\n\n        if (!skipUserTask) {\n            handleAssignments(activeAssigneeExpression, activeOwnerExpression, activeCandidateUserExpressions,\n                    activeCandidateGroupExpressions, task, activityExecution);\n\n            task.fireEvent(TaskListener.EVENTNAME_CREATE);\n\n            // All properties set, now firing 'create' events\n            if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {\n                Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(\n                        ActivitiEventBuilder.createEntityEvent(FlowableEngineEventType.TASK_CREATED, task),\n                        EngineConfigurationConstants.KEY_PROCESS_ENGINE_CONFIG);\n            }\n        }","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java#L188-L224","documentation":"Thrown when the formKey expression of a user task (activiti:formKey) evaluates to a non-null value that is not a String during UserTaskActivityBehavior.execute(). The engine requires the form key to be a String and includes the raw expression text in the message. Null results are tolerated; any other type is not.","triggerScenarios":"Starting/reaching a user task whose formKey attribute holds an expression like ${formId} where formId is a Long/Integer variable or a bean method returning a non-String.","commonSituations":"Numeric form keys defined as numeric process variables; a form key expression referencing a counter or enum constant; copy-pasted form key referencing the wrong variable type after refactoring.","solutions":["Coerce the expression to a String, e.g. ${formId.toString()}","Change the process variable or bean getter referenced by the expression to return String","Prefix the value or use string concatenation so the expression evaluates to a String","Remove the formKey expression if a form key is not needed"],"exampleFix":"// before\n<userTask id=\"approve\" activiti:formKey=\"${formNumber}\" />\n// after\n<userTask id=\"approve\" activiti:formKey=\"${formNumber.toString()}\" />","handlingStrategy":"validation","validationCode":"Object v = ((ExecutionEntity) execution).getVariable(\"formId\");\nif (v != null && !(v instanceof String)) {\n    throw new IllegalArgumentException(\"formId must be a String, got \" + v.getClass());\n}","typeGuard":"if (formKey instanceof String) { task.setFormKey((String) formKey); }","tryCatchPattern":"try {\n    runtimeService.startProcessInstanceByKey(key, vars);\n} catch (ActivitiIllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"FormKey expression\")) { /* coerce variable */ }\n    throw e;\n}","preventionTips":["Keep form keys as String variables/attributes in the process model","Use ${value.toString()} when referencing numeric ids in formKey","Validate expression return types with a startup/model test"],"tags":["expression","bpmn","form-key","user-task"],"backgroundTag":"type-mismatch","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}