flowable/flowable-engine · error · FlowableIllegalArgumentException
Task has no form defined
Error message
Task has no form defined
What it means
getTaskForm in HistoricTaskInstanceResource looks up the historic task instance, and if its formKey is empty/null it throws this FlowableIllegalArgumentException instead of returning a form. A historic task without a stored form key has no form definition to render, so the endpoint refuses to proceed.
Source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/history/HistoricTaskInstanceResource.java:94
HistoricTaskInstance task = getHistoricTaskInstanceFromRequestWithoutAccessCheck(taskId);
if (restApiInterceptor != null) {
restApiInterceptor.deleteHistoricTask(task);
}
historyService.deleteHistoricTaskInstance(taskId);
}
@ApiOperation(value = "Get a historic task instance form", tags = { "History Task" }, nickname = "getHistoricTaskForm")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Indicates request was successful and the task form is returned"),
@ApiResponse(code = 404, message = "Indicates the requested task was not found.")
})
@GetMapping(value = "/history/historic-task-instances/{taskId}/form", produces = "application/json")
public String getTaskForm(@ApiParam(name = "taskId") @PathVariable String taskId) {
HistoricTaskInstance task = getHistoricTaskInstanceFromRequest(taskId);
if (StringUtils.isEmpty(task.getFormKey())) {
throw new FlowableIllegalArgumentException("Task has no form defined");
}
FormInfo formInfo = taskService.getTaskFormModel(task.getId());
if (formHandlerRestApiInterceptor != null) {
return formHandlerRestApiInterceptor.convertHistoricTaskFormInfo(formInfo, task);
} else {
SimpleFormModel formModel = (SimpleFormModel) formInfo.getFormModel();
return restResponseFactory.getFormModelString(new FormModelResponse(formInfo, formModel));
}
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Check the historic task's formKey (GET .../historic-task-instances/{taskId}) before requesting the form.
- Set a form key on the task/definition if the form should exist (taskService.setFormKey or in the BPMN userTask definition).
- Handle FlowableIllegalArgumentException with HTTP 409/400 semantics client-side and show 'no form available'.
Example fix
// before
String form = get("/history/historic-task-instances/" + taskId + "/form");
// after
HistoricTaskInstance t = get(".../historic-task-instances/" + taskId);
if (t.getFormKey() == null || t.getFormKey().isEmpty()) return null;
String form = get(".../historic-task-instances/" + taskId + "/form"); Defensive patterns
Strategy: validation
Validate before calling
const task = await get(`/history/historic-task-instances/${taskId}`);
if (!task.formKey) throw new Error('Task has no form defined: ' + taskId); Type guard
function hasForm(task) { return typeof task.formKey === 'string' && task.formKey.length > 0; } Try / catch
try { return getForm(taskId) } catch (e) { if (String(e.message) === 'Task has no form defined') return null; throw e } Prevention
- Fetch the historic task and check formKey before requesting its form
- Set form keys on task definitions when forms are expected
- Treat missing form as a normal business case, not an outage
When it happens
Trigger: GET /history/historic-task-instances/{taskId}/form for a task that was completed without a form key, or whose form key was never set at task creation.
Common situations: Tasks created programmatically (no formKey); tasks from definitions without forms; querying forms for deleted/stale historic rows; clients assuming every historic task has a form.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Task has no form defined
- Unsupported variable query operation:
- Variable operation is missing for variable:
- Variable value is missing for variable:
- formInfo is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/945bbab932c420e8.
Report an issue: GitHub.