flowable/flowable-engine · error · FlowableIllegalArgumentException
groupId is null
Error message
groupId is null
What it means
DeleteMembershipCmd.execute() validates both membership key components; this error is raised when groupId is null (after the userId check passed). A membership cannot be located without both userId and groupId.
Solutions
- Pass a non-null groupId to IdentityService.deleteMembership().
- Resolve the group by name first and fail with a clear 'group not found' error if the lookup yields null.
- Validate both parameters at the service/UI boundary before calling the engine.
- Catch FlowableIllegalArgumentException and map it to a 400-style validation response.
Example fix
// before identityService.deleteMembership(userId, groupId); // groupId may be null // after Objects.requireNonNull(groupId, "groupId is required to delete a membership"); identityService.deleteMembership(userId, groupId);
Defensive patterns
Strategy: validation
Validate before calling
if (groupId == null) {
throw new IllegalArgumentException("groupId must be provided before deleting a membership");
}
if (userId == null) {
throw new IllegalArgumentException("userId must be provided before deleting a membership");
} Type guard
boolean hasValidMembershipKey(String userId, String groupId) {
return userId != null && groupId != null;
} Try / catch
try {
identityService.deleteMembership(userId, groupId);
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("groupId is null")) {
throw new InvalidRequestException("groupId is required to delete a membership");
}
throw e;
} Prevention
- Resolve groups by name with an explicit not-found error before using the id.
- Keep the (userId, groupId) argument order consistent; swap mistakes often yield nulls.
- Validate both parameters at the service boundary before invoking the engine.
- Never pass optional/nullable group fields straight into deleteMembership.
When it happens
Trigger: Calling IdentityService.deleteMembership(userId, null), or new DeleteMembershipCmd(userId, null); typically when the group id comes from a lookup that returned nothing or an unset form field.
Common situations: Removing a user from a group whose id was resolved by name and the name lookup failed; admin UI sending only userId; refactoring where parameter order was changed and groupId fell through as null.
Related errors
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/324a478d0eb76af7.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-idm-engine/src/main/java/org/flowable/idm/engine/impl/cmd/DeleteMembershipCmd.java:42
*/
public class DeleteMembershipCmd implements Command<Void>, Serializable {
private static final long serialVersionUID = 1L;
String userId;
String groupId;
public DeleteMembershipCmd(String userId, String groupId) {
this.userId = userId;
this.groupId = groupId;
}
@Override
public Void execute(CommandContext commandContext) {
if (userId == null) {
throw new FlowableIllegalArgumentException("userId is null");
}
if (groupId == null) {
throw new FlowableIllegalArgumentException("groupId is null");
}
CommandContextUtil.getMembershipEntityManager(commandContext).deleteMembership(userId, groupId);
return null;
}
}
View on GitHub (pinned to d6d39ce1c6)