YunaiV/yudao-cloud · error · IllegalArgumentException
非法的 conversationType: {}
Error message
非法的 conversationType: {} What it means
ImRtcCallServiceImpl's create-call validation throws IllegalArgumentException when conversationType is neither the private nor the group value recognized by ImConversationTypeEnum.isPrivate/isGroup. This is the terminal fallback after the private branch (which validates peerUserId/inviteeIds) and the group branch (which requires groupId, non-empty inviteeIds and caller membership) — so the value is not merely wrong, it is unhandled entirely.
Source
Thrown at yudao-module-im/yudao-module-im-server/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java:868
Long peerUserId = CollUtil.getFirst(reqVO.getInviteeIds());
if (ObjUtil.equal(userId, peerUserId)) {
throw exception(RTC_INVITE_SELF);
}
friendService.validateFriend(userId, peerUserId);
return;
}
if (ImConversationTypeEnum.isGroup(conversationType)) {
if (reqVO.getGroupId() == null) {
throw exception(RTC_GROUP_REQUIRED);
}
// 群通话必须前端选中被邀请人(对齐微信);空集合直接拒
if (CollUtil.isEmpty(reqVO.getInviteeIds())) {
throw exception(RTC_GROUP_INVITEE_REQUIRED);
}
groupMemberService.validateMemberInGroup(reqVO.getGroupId(), userId);
return;
}
throw new IllegalArgumentException("非法的 conversationType: " + conversationType);
}
/**
* 解析被邀请池:私聊为 peerUserId 单元素;群聊为前端选中子集(超量抛错)
*
* @param reqVO 创建请求
* @param inviterId 发起人编号;自己不进被邀请池
* @return 被邀请人 userId 集合
*/
private Set<Long> resolveInvitees(ImRtcCallCreateReqVO reqVO, Long inviterId) {
// 1. 私聊:inviteeIds 已在 validateCreateCall 校验仅 1 个对端,直接复用
if (ImConversationTypeEnum.isPrivate(reqVO.getConversationType())) {
return new LinkedHashSet<>(reqVO.getInviteeIds());
}
// 2. 群聊校验:被邀请人必须是该群活跃成员,防止恶意客户端塞任意 userId
groupMemberService.validateMembersInGroup(reqVO.getGroupId(), reqVO.getInviteeIds());
Set<Long> initial = new LinkedHashSet<>(reqVO.getInviteeIds());View on GitHub (pinned to 477be9dd49)
Solutions
- Send a conversationType defined by ImConversationTypeEnum (private value for 1v1 calls, group value for group calls)
- For group calls also pass groupId and a non-empty inviteeIds; for private calls pass the single peer
- Align app and server IM module versions
Example fix
// before
{"conversationType":0,"inviteeIds":[2]}
// after
{"conversationType":1,"peerUserId":2} // private
// or
{"conversationType":2,"groupId":10,"inviteeIds":[2,3]} // group Defensive patterns
Strategy: type-guard
Validate before calling
Integer ct = reqVO.getConversationType();
if (!ImConversationTypeEnum.isPrivate(ct) && !ImConversationTypeEnum.isGroup(ct)) {
throw new IllegalArgumentException("conversationType 必须为 私聊 或 群聊");
} Type guard
boolean isKnownConversationType(Integer ct) {
return ImConversationTypeEnum.isPrivate(ct) || ImConversationTypeEnum.isGroup(ct);
} Prevention
- Send conversationType from a shared enum, never free-form
- Make the field required in the request VO so absent values 400 early
- For group calls, pre-check groupId + non-empty inviteeIds client-side
When it happens
Trigger: POST create RTC call with conversationType missing/null (falls through if not private), 0, or a future value like 'system'; frontend sending its own enum spelling ('single' instead of the numeric/constant the server expects); deserialization defaulting to 0 when the field is absent.
Common situations: Frontend/backend enum drift after an IM module upgrade; new conversation type added to the app before server support; JSON payload omitting conversationType so the field defaults.
Related errors
AI-assisted analysis of YunaiV/yudao-cloud@477be9dd49 (2026-08-14).
Data as JSON: /api/errors/ee858e12d693317f.
Report an issue: GitHub.