flowable/flowable-engine · error · FlowableException

No formEngine '

Error message

No formEngine '

What it means

GetRenderedTaskFormCmd.execute looks up a FormEngine by name from processEngineConfiguration.getFormEngines() and throws FlowableException when the map contains no entry for the requested formEngineName. The engine only registers built-in form engines (e.g. 'juel') at configuration time, so a name that was never registered cannot render the task form.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/GetRenderedTaskFormCmd.java:67

        if (taskId == null) {
            throw new FlowableIllegalArgumentException("Task id should not be null");
        }

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskEntity task = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);
        if (task == null) {
            throw new FlowableObjectNotFoundException("Task '" + taskId + "' not found", Task.class);
        }

        FormHandlerHelper formHandlerHelper = processEngineConfiguration.getFormHandlerHelper();
        TaskFormHandler taskFormHandler = formHandlerHelper.getTaskFormHandlder(task);
        if (taskFormHandler != null) {

            FormEngine formEngine = processEngineConfiguration.getFormEngines().get(formEngineName);

            if (formEngine == null) {
                throw new FlowableException("No formEngine '" + formEngineName + "' defined process engine configuration");
            }

            TaskFormData taskForm = taskFormHandler.createTaskForm(task);

            return formEngine.renderTaskForm(taskForm);
        }

        return null;
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Pass a registered form engine name (default 'juel') or omit the formEngineName argument so the default is used
  2. Register your custom FormEngine on the ProcessEngineConfiguration (engineConfig.setFormEngines(map-with-your-engine) or add via an EngineConfigurator) before starting the engine
  3. Log processEngineConfiguration.getFormEngines().keySet() at startup and match your requested name against it
  4. If the process definition has no task form, guard the null taskFormHandler branch instead of relying on form rendering

Example fix

// before
String rendered = formService.getRenderedTaskForm(taskId, "myFormEngine");
// after
String rendered = formService.getRenderedTaskForm(taskId, "juel"); // or register the engine:
configuration.setFormEngines(Map.of("myFormEngine", new MyFormEngine()));
Defensive patterns

Strategy: validation

Validate before calling

if (!processEngineConfiguration.getFormEngines().containsKey(formEngineName)) {
    throw new IllegalArgumentException("Unknown form engine: " + formEngineName);
}

Type guard

boolean hasFormEngine(String name) {
    return name != null && processEngineConfiguration.getFormEngines().containsKey(name);
}

Try / catch

try {
    return formService.getRenderedTaskForm(taskId, engineName);
} catch (FlowableException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("No formEngine")) {
        return formService.getRenderedTaskForm(taskId, "juel"); // fall back to default engine
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling TaskService.getRenderedTaskForm(taskId) or FormService.getRenderedTaskForm with a taskFormEngineName that is not a key in ProcessEngineConfigurationImpl.formEngines.

Common situations: Typo in the form engine name passed to the form property/ API call; using a name from an older Activiti version ('form' engine removed/renamed); building a custom engine config that disables default form engines; copy-pasted config referencing a custom FormEngine that was never added via processEngineConfiguration.setFormEngines(...) or a custom EngineConfigurator.

Related errors


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