The why is probably, because the client came from a different background than embedded.
DERBY-3801 I mentioned I took a quick look and thought it was possible to pass on the operation that caused the CLIENT_RESULT_SET_NOT_OPEN to be passed on. But I'm not a client/server/drda expert, so perhaps I'm wrong.
To pull these two messages together, without losing helpful information, the thing to do would be to add the information about the operation causing the error situation to be propogated.
You cannot simply replace CLIENT_RESULT_SET_NOT_OPEN by LANG_RESULT_SET_NOT_OPEN, because the LANG one has an additional parameter, that's not available right now for the CLIENT one. You'd get NPEs at worst, empty strings at best. So, some work is involved in finding what the operation is in each call for the CLIENT one.
As the CLIENT one seems to be called from one of two methods (client.am.ResultSet.checkForClosedResultSet(), and client.am.SectionManager()), those methods will need to be changed to pass the operation through. Judging by the usage of LANG_RESULT_SET_NOT_OPEN, depending on the situation, either variables for the operation strings (like they're defined for the LANG message in e.g. impl.sql.execute.BasicNoPutResultSetImpl.java) will have to get defined somewhere (I don't know the best place for that, but I believe the client code has a central place for strings like that), or they can be hardcoded/ad hoc (like e.g. in MaterializedResultSet).
(note, the operations are commands, not language constructs/messages, so don't need to be translated, and thus, can be hardcoded).