{"record":{"id":"faddc370c7b30a88","repo":"flowable/flowable-engine","slug":"userid-is-null-faddc3","errorCode":null,"errorMessage":"userId is null","messagePattern":"userId is null","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-idm-engine/src/main/java/org/flowable/idm/engine/impl/cmd/DeleteMembershipCmd.java","lineNumber":39,"sourceCode":"\n/**\n * @author Tom Baeyens\n */\npublic class DeleteMembershipCmd implements Command<Void>, Serializable {\n\n    private static final long serialVersionUID = 1L;\n    String userId;\n    String groupId;\n\n    public DeleteMembershipCmd(String userId, String groupId) {\n        this.userId = userId;\n        this.groupId = groupId;\n    }\n\n    @Override\n    public Void execute(CommandContext commandContext) {\n        if (userId == null) {\n            throw new FlowableIllegalArgumentException(\"userId is null\");\n        }\n        if (groupId == null) {\n            throw new FlowableIllegalArgumentException(\"groupId is null\");\n        }\n\n        CommandContextUtil.getMembershipEntityManager(commandContext).deleteMembership(userId, groupId);\n\n        return null;\n    }\n\n}\n","sourceCodeStart":21,"sourceCodeEnd":51,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-idm-engine/src/main/java/org/flowable/idm/engine/impl/cmd/DeleteMembershipCmd.java#L21-L51","documentation":"DeleteMembershipCmd.execute() validates both userId and groupId before removing the membership; this error is raised when userId is null. Membership is keyed by the (userId, groupId) pair, so neither component may be null.","triggerScenarios":"Calling IdentityService.deleteMembership(null, groupId), or constructing DeleteMembershipCmd with a null userId, e.g. when removing a user's group links during user deletion where the user object/id was never loaded.","commonSituations":"User-deletion cleanup code where the user id variable is null because the user was already deleted; REST endpoints accepting optional userId; copy-paste between deleteMembership calls swapping or dropping arguments.","solutions":["Pass a non-null userId (and groupId) to IdentityService.deleteMembership().","Load the user first and use its verified id rather than an optional/nulled field.","Guard the call: skip membership deletion when userId is null and log the condition instead.","Catch FlowableIllegalArgumentException to translate it into an application validation error."],"exampleFix":"// before\nidentityService.deleteMembership(userId, groupId); // userId may be null\n\n// after\nif (userId != null && groupId != null) {\n    identityService.deleteMembership(userId, groupId);\n}","handlingStrategy":"validation","validationCode":"if (userId == null) {\n    throw new IllegalArgumentException(\"userId must be provided before deleting a membership\");\n}\nif (groupId == null) {\n    throw new IllegalArgumentException(\"groupId must be provided before deleting a membership\");\n}","typeGuard":"boolean hasValidMembershipKey(String userId, String groupId) {\n    return userId != null && groupId != null;\n}","tryCatchPattern":"try {\n    identityService.deleteMembership(userId, groupId);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"is null\")) {\n        throw new InvalidRequestException(\"Both userId and groupId are required to delete a membership\");\n    }\n    throw e;\n}","preventionTips":["Always resolve both user and group entities before membership operations.","During user deletion cleanup, reuse the verified user id instead of a nullable field.","Mirror the engine's null checks (userId first, then groupId) in your own validation for clearer errors.","Add integration tests for membership CRUD with missing parameters."],"tags":["flowable","idm","null-check","membership"],"backgroundTag":"null-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T16:30:33.424Z"}